2017-02-09 68 views
1

考虑以下代码:电话constexpr函数接受的阵列编译失败

#include <array> 

template < int... Ints > 
constexpr std::array<int,sizeof...(Ints)> theIntArray = {Ints...}; 

template < size_t NN > 
constexpr void test(const std::array<int,NN>& xx) 
{ 
    theIntArray<xx[0]>; 
} 

constexpr std::array<int,2> aa = {10,20}; 

int main() 
{ 
    theIntArray<aa[0]>; // passes 
    test(aa); // FAILS ?! 

    return 0; 
} 

main()功能的第一线通过,而第二线失败,奇怪的错误消息:

error: ‘* & xx’ is not a constant expression 
note: in template argument for type ‘int’ 

我使用的是gcc-7.0.1,你可以找到现场示例here

这是根据标准还是它是一个错误?第一条线经过时,什么使第二条线失败?

回答

2

所有constexpr函数必须对constexpr和非constexpr参数都有效。或者,简而言之,constexpr函数的参数不是在体内的constexpr,但如果它们在函数体外部是constexpr,则从函数返回的依赖于它们的certian计算可能是constexpr

theIntArray<xx[0]>; 

这是唯一有效的语法,如果xx[0]constexpr,但功能体xx内是constexpr

template < size_t NN, std::array<int,NN> const& xx > 
constexpr void test() 
{ 
    theIntArray<xx[0]>; 
} 

live example

+0

TIL将常量引用添加到文字类型以模仿用户定义的非类型模板参数。 upvoted。 – TemplateRex

1

区别在于constexpr函数参数不存在。也就是说,你不能做

constexpr auto fun(int x) { 
    constexpr y = x; 
    return y; 
} 

,而且您可以使用函数参数xx[0]作为函数内的非类型模板参数。这与aa[0]不同,因为它是在函数之外进行评估的。

做你想做的事情的唯一方法就是使函数参数成为一个非类型的模板参数。要做到这一点,请参阅@Yakk的答案,他使用对constexpr数组的常量引用作为非类型模板参数。