在回答我的问题时 Avoiding struct in variadic template function iavr评论说“std :: array :: operator []仅在C ++ 14中是constexpr”。我的 这里的问题是确保GCC行为不一致,而不是 我错误地理解了标准。
我正在探索使用一些模板元编程的不同方式 将二维数组初始化为Pascal三角形(外部为0)。 在我正在尝试的那个,我想尽可能避免使用 模板结构,特别是变量有利,如果constexpr功能 和数组。
匆忙注意读者:我为了这个目的而放了以下三段代码 完整性,但你不需要理解它们。
我正在使用以下两个非常标准的定义:
template <typename... Ts> struct Sequence {};
template<unsigned N, unsigned... Is> struct Range {
typedef typename Range<N-1, N-1, Is...>::type type;
};
template<unsigned... Is> struct Range<0, Is...> {
typedef Sequence<std::integral_constant<unsigned int, Is>...> type;
};
然后我有以下模板constexpr函数给出了一行 三角形,计算下一个:
// nextline
template <typename... SeqTis, typename T, size_t Size>
constexpr std::array<T, Size>
nextline(Sequence<SeqTis...>, const typename std::array<T, Size> ar) {
return { 1, (ar[SeqTis::value]+ar[SeqTis::value+1])... };
}
template <typename T, size_t Size>
constexpr std::array<T, Size>
nextline(const typename std::array<T, Size> ar) {
return nextline(typename Range<Size-1>::type(), ar);
}
以下在部分初始化数组的末尾添加一个元素:
template <typename... SeqTis, typename T, size_t Size>
constexpr std::array<T, Size>
appendarray(Sequence<SeqTis...>, const typename std::array<T, Size> ar, const T el) {
return { ar[SeqTis::value]..., el };
}
template <size_t Pos, typename T, size_t Size>
constexpr std::array<T, Size>
appendarray(const typename std::array<T, Size> ar, const T el) {
return appendarray(typename Range<Pos>::type(), ar, el);
}
在这些代码中,我使用的是数组索引,它完美无缺。你可以试试 用:
constexpr auto ar0 = std::array<int, 3> { 1,0,0 };
constexpr auto ar1 = nextline(ar0);
constexpr auto ar2 = appendarray<2>(ar1, 12);
for (auto i: ar2) std::cout << i << " "; // prints 1 1 12
但是当我尝试编译以下递归结构时:
template <typename T, size_t N>
using Ar2 = std::array<std::array<T, N+1>, N+1>;
template<typename T, size_t N, size_t l> struct Loop {
constexpr static Ar2<T, N> next() {
return appendarray<l>(Loop<T, N, l-1>::next(),
nextline(Loop<T, N, l-1>::next()[l-1]));
}
};
template<typename T, size_t N> struct Loop<T, N, 0> {
constexpr static Ar2<T, N> next() {
return Ar2<T, N>({ {1, 0} });
}
};
};
然后GCC抱怨
[...]
binom2.cpp:48:30: note: ‘static constexpr Ar2<T, N> Loop<T, N, l>::next() [with T = long long int; long unsigned int N = 10ul; long unsigned int l = 10ul; Ar2<T, N> = std::array<std::array<long long int, 11ul>, 11ul>]’ is not usable as a constexpr function because:
constexpr static Ar2<T, N> next() {
^
binom2.cpp:50:38: error: call to non-constexpr function ‘std::array<_Tp, _Nm>::value_type& std::array<_Tp, _Nm>::operator[](std::array<_Tp, _Nm>::size_type) [with _Tp = std::array<long long int, 11ul>; long unsigned int _Nm = 11ul; std::array<_Tp, _Nm>::reference = std::array<long long int, 11ul>&; std::array<_Tp, _Nm>::value_type = std::array<long long int, 11ul>; std::array<_Tp, _Nm>::size_type = long unsigned int]’
nextline(Loop<T, N, l-1>::next()[l-1]));
似乎有时GCC允许constexpr数组索引,有时它 没有。我错过了什么。
答案 0 :(得分:2)
据我了解,
T& std::array<T,N>::operator[]
不是constexpr,而是
constexpr const T& std::array<T,N>::operator[] const
是......你必须手动转换任何返回带有(const std :: array&amp;)的(非const)std :: array的东西,以使它选择correect运算符。
在使用强制语法进行一些讨论之后,看起来正确的语法是:
nextline(((const Ar2<T, N>&) Loop<T, N, l-1>::next())[l-1])
虽然您可能仍然希望查看const_cast,因为常规强制转换将删除函数调用的右值。
答案 1 :(得分:0)
最简单的解决方法是声明next
函数返回constexpr const数组:
template<typename T, size_t N, size_t l> struct Loop {
constexpr const static Ar2<T, N> next() {
return appendarray<l>(Loop<T, N, l-1>::next(),
nextline(Loop<T, N, l-1>::next()[l-1]) );
}
};