8a7109f9c5
gcc 11.2.0 compiles us just fine but clang 13.0.1 fails with this error clang++ -DKAK_DEBUG -O0 -pedantic -std=c++2a -g -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare -Wno-address -frelaxed-template-template-args -Wno-ambiguous-reversed-operator -MD -MP -MF .ranges.debug.d -c -o .ranges.debug.o ranges.cc ranges.cc:30:17: error: no viable constructor or deduction guide for deduction of template arguments of 'Array' check_equal(Array{{""_sv, "abc"_sv, ""_sv, "def"_sv, ""_sv}} | flatten(), "abcdef"_sv); ^ ./constexpr_utils.hh:14:8: note: candidate template ignored: couldn't infer template argument 'T' struct Array ^ ./constexpr_utils.hh:14:8: note: candidate function template not viable: requires 0 arguments, but 1 was provided 1 error generated. The same error can be reproduced with this C++ input template<typename T, int N> struct Array { T m_data[N]; }; void test() { (void)Array{{1, 2}}; } Since "Array" has no constructor, the compiler uses aggregate initialization. Only recent g++ seems to be smart enough to deduce template arguments in this case. Help other compilers by adding a deduction guide. The deduction guide needs to count the array elements to infer the array size, hence we need to remove braces. Happily, this is allowed and it's also what std::array does. Closes #4597
91 lines
2.5 KiB
C++
91 lines
2.5 KiB
C++
#ifndef constexpr_utils_hh_INCLUDED
|
|
#define constexpr_utils_hh_INCLUDED
|
|
|
|
#include <utility>
|
|
#include <initializer_list>
|
|
#include <stddef.h>
|
|
|
|
#include "array_view.hh"
|
|
|
|
namespace Kakoune
|
|
{
|
|
|
|
template<typename T, size_t N>
|
|
struct Array
|
|
{
|
|
constexpr size_t size() const { return N; }
|
|
constexpr const T& operator[](int i) const { return m_data[i]; }
|
|
constexpr const T* begin() const { return m_data; }
|
|
constexpr const T* end() const { return m_data+N; }
|
|
|
|
constexpr T& operator[](int i) { return m_data[i]; }
|
|
constexpr T* begin() { return m_data; }
|
|
constexpr T* end() { return m_data+N; }
|
|
|
|
constexpr operator ArrayView<T>() { return {m_data, N}; }
|
|
constexpr operator ConstArrayView<T>() const { return {m_data, N}; }
|
|
|
|
T m_data[N];
|
|
};
|
|
|
|
template<typename T, typename... U> requires (std::is_same_v<T, U> and ...)
|
|
Array(T, U...) -> Array<T, 1 + sizeof...(U)>;
|
|
|
|
template<typename T, size_t N, size_t... Indices>
|
|
constexpr Array<T, N> make_array(const T (&data)[N], std::index_sequence<Indices...>)
|
|
{
|
|
static_assert(sizeof...(Indices) == N, "size mismatch");
|
|
return {{data[Indices]...}};
|
|
}
|
|
|
|
template<typename T, size_t N>
|
|
constexpr Array<T, N> make_array(const T (&data)[N])
|
|
{
|
|
return make_array(data, std::make_index_sequence<N>());
|
|
}
|
|
|
|
template<typename T, size_t capacity>
|
|
struct ConstexprVector
|
|
{
|
|
using iterator = T*;
|
|
using const_iterator = const T*;
|
|
|
|
constexpr ConstexprVector() : m_size{0} {}
|
|
constexpr ConstexprVector(std::initializer_list<T> items)
|
|
: m_size{items.size()}
|
|
{
|
|
T* ptr = m_data;
|
|
for (auto& item : items)
|
|
*ptr++ = std::move(item);
|
|
}
|
|
|
|
constexpr bool empty() const { return m_size == 0; }
|
|
constexpr size_t size() const { return m_size; }
|
|
|
|
constexpr void resize(size_t n, const T& val = {})
|
|
{
|
|
if (n >= capacity)
|
|
throw "capacity exceeded";
|
|
for (int i = m_size; i < n; ++i)
|
|
m_data[i] = val;
|
|
m_size = n;
|
|
kak_assert(this->size() == m_size); // check for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79520
|
|
}
|
|
|
|
constexpr T& operator[](size_t i) { return m_data[i]; }
|
|
constexpr const T& operator[](size_t i) const { return m_data[i]; }
|
|
|
|
constexpr iterator begin() { return m_data; }
|
|
constexpr iterator end() { return m_data + m_size; }
|
|
|
|
constexpr const_iterator begin() const { return m_data; }
|
|
constexpr const_iterator end() const { return m_data + m_size; }
|
|
|
|
size_t m_size;
|
|
T m_data[capacity] = {};
|
|
};
|
|
|
|
}
|
|
|
|
#endif // constexpr_utils_hh_INCLUDED
|