为什么这不是一个常数表达式
Why is this not a constant expression?
在这个简单的示例中,即使test1
成功,test2
也无法编译,我不明白为什么会出现这种情况。如果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
}
简答:C++11/14
中没有constexpr
函数参数
更详细的回答:在test1()
中,如果i
不是编译时常数,该函数在运行时仍然可用。但是在test2()
中,编译器无法知道i
是否是一个编译时常数,而函数却需要它来编译。
。以下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
不是一个常量表达式,这意味着你不能在f1
中实例化x
或k
的模板。
对于constexpr
在这里的作用存在误解。它表明函数必须在编译时对合适的参数可求值,但是并没有消除在一般情况下仍然需要编译的要求。
让我们看第一个版本:
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i) {
return arr[i];
}
现在,这显然是一个编译时的求值:
enum { CompileTimeConstant = test1("Test", 0) };
你的例子可能是,但这是一个优化器/qi问题:
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
不可能在最后一种情况下编译,它根本不能编译。(请注意,我不是建议代码好)。
这里的问题是调用arr[i]
会调用下标操作符operator[]
。
这实际上不是constexpr
的问题,是模板参数演绎的问题。非类型模板实参必须是下标操作符的返回实参不是的常量表达式。
因此,编译器有理由抱怨arr[i]
不是一个常量表达式。
因为arr[i]
不是编译时常量表达式。
你可以用动态数组大小来修复它。你可以使用vector类,因为在vector类中你可以动态地调整列表的大小。或者你可以使用malloc,但是当向量类还在那里的时候,这样做会浪费时间。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 运行同一解决方案的另一个项目的项目
- 挂起和取消挂起一个文件DLL
- 用C++中的一个变量定义一个常量
- 函数向量_指针有不同的原型,我可以构建一个吗
- 为什么 g++ 使用 movabs 和一个奇怪的常数来简单还原?
- 在CUDA内核中传递一个常数整数
- 我可以定义一个(键入的)常数,该常数确定不占据可执行文件中的空间
- 为什么一个表达是常数,而不是另一个表达
- 在另一个带有名称空间的标头文件中定义常数
- strstr 返回如何不是一个常数
- 为什么不允许将右值引用绑定到非常数引用,而允许在其中一个上调用非常数成员函数
- 在C++中,我应该在什么时候使一个方法为常数
- 一个数据结构的线性时间构造,如果两个字符串有两个共同的字母,则在常数时间内回答
- 为什么这不是一个常数表达式
- 我无法用我的实际知识解决一个转瞬即逝的常数错误
- 调用一个具有非常数指针的函数会重新解析为一个模板函数,而不是一个具有指向常量指针的函数
- 太阳工作室10有一个奇怪的“太阳”常数