在这个简单的例子中,即使test2
成功,test1
也无法编译,我不明白为什么会这样。如果arr[i]
适合来自标记为constexpr
的函数的返回值,那为什么它不能用作非类型模板参数?
template<char c>
struct t
{
static const char value = c;
};
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i)
{
return arr[i];
}
template <unsigned N>
constexpr char test2(const char (&arr)[N], unsigned i)
{
return t<arr[i]>::value;
}
int main()
{
char a = test1("Test", 0); //Compiles OK
char b = test2("Test", 0); //error: non-type template argument
//is not a constant expression
}
编辑:这没有区别:
template<char c>
struct t
{
static const char value = c;
};
template <unsigned N>
constexpr char test1(const char (&arr)[N])
{
return arr[0];
}
template <unsigned N>
constexpr char test2(const char (&arr)[N])
{
return t<arr[0]>::value;
}
int main()
{
char a = test1("Test"); //Compiles OK
char b = test2("Test"); //error: non-type template argument
//is not a constant expression
}
答案 0 :(得分:22)
简答:constexpr
中没有C++11/14
个函数参数。
更长的答案:在test1()
中,如果i
不是编译时常量,则该函数在运行时仍然可用。但是在test2()
中,编译器无法知道i
是否是编译时常量,但是函数需要编译。
E.g。 test1
的以下代码将编译
int i = 0;
char a = test1("Test", i); // OK, runtime invocation of test1()
constexpr int i = 0;
constexpr char a = test1("Test", i); // also OK, compile time invocation of test1()
让我们只是你的test2()
到
constexpr char test3(unsigned i)
{
return t<i>::value;
}
这不会为test3(0)
编译,因为在test3()
内,无法证明i
是无条件编译时表达式。您需要constexpr
个函数参数来表达它。
5.19常量表达式[expr.const]
2条件表达式e是核心常量表达式,除非 评估e,遵循抽象机的规则(1.9), 将评估以下表达式之一:
- 一个引用变量或数据成员的id表达式 引用类型,除非引用具有先前的初始化和 无论是
初始化
- 使用常量表达式- 它是一个对象的非静态数据成员,其生命周期始于e;
的评估中
此部分包含与您的问题对应的以下代码示例:
constexpr int f1(int k) {
constexpr int x = k; // error: x is not initialized by a
// constant expression because lifetime of k
// began outside the initializer of x
return x;
}
由于上例中的x
不是常量表达式,因此意味着您无法在x
内实例化k
或f1
的模板。
答案 1 :(得分:7)
对constexpr
在这里所做的事情存在误解。它表明函数必须在编译时可以为适当的参数进行求值,但它确实不在一般情况下仍然需要编译。
我们来看第一个版本:
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i) {
return arr[i];
}
现在,这显然是编译时的评估:
enum { CompileTimeConstant = test1("Test", 0) };
您的示例可能,但这是优化程序/ QoI问题:
char MayBeCompileTimeConstant = test1("Test", 0);
这个例子显然不是,但仍然需要是可评估的
char arr[10];
int i;
std::cin >> i;
std::cin >> arr;
char b = test1(arr, i);
std::cout << "'" << arr << "'[" << i << "] = " << b << '\n';
由于test2
无法为最后一种情况编译,因此根本无法编译。 (请注意,我并不是说代码好)。
答案 2 :(得分:2)
这里的问题是调用arr[i]
会唤起下标运算符operator[]
。 此运算符不会返回常量表达式。
实际上它不是constexpr
的问题,是模板参数推导的问题。非类型模板参数必须是常量表达式,下标运算符的返回参数不是。
因此,编译器理所当然地抱怨arr[i]
不是常量表达式。
答案 3 :(得分:1)
因为arr[i]
不是编译时常量表达式。它在运行时可能会有所不同。