首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这不是一个固定的表达方式呢?

为什么这不是一个固定的表达方式呢?
EN

Stack Overflow用户
提问于 2014-07-04 21:04:20
回答 5查看 54.6K关注 0票数 29

在这个简单的例子中,即使test2成功了,test1也无法编译,我不明白为什么会这样。如果arr[i]适合于从标记为constexpr的函数返回值,那么为什么不能将其用作非类型模板参数?

代码语言:javascript
复制
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
}

编辑:这没有什么区别:

代码语言:javascript
复制
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
}
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2014-07-04 21:08:45

简单回答:在constexpr中没有C++11/14函数参数。

更长的答案:在test1()中,如果i不是编译时常量,则该函数在运行时仍然可用。但是在test2()中,编译器不知道i是否是编译时常量,但它是函数编译所必需的。

例如,test1的以下代码将编译

代码语言:javascript
复制
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()

代码语言:javascript
复制
constexpr char test3(unsigned i)
{
    return t<i>::value;
}

这不会为unconditional编译test3(0),因为在test3()内部,无法证明i是一个编译时表达式。您需要constexpr函数参数才能表达这一点。

引用标准

5.19常数表达式expr.const

2条件表达式e是核心常量表达式,除非e的计算遵循抽象机器(1.9)的规则计算下列表达式之一: -一个id-表达式,它引用引用类型的变量或数据成员,除非引用具有前面的初始化,并且 -它由常量表达式初始化,或 -它是一个对象的非静态数据成员,其寿命在e的评估范围内开始;

本节有与您的问题相应的以下代码示例:

代码语言:javascript
复制
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中使用xk实例化模板。

票数 30
EN

Stack Overflow用户

发布于 2014-07-04 21:32:18

对于constexpr在这里所做的事情,有一种误解。它指出,函数必须在编译时对合适的参数进行评估,但在一般情况下,它不会删除仍然需要编译的要求。

让我们来看第一个版本:

代码语言:javascript
复制
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i) {
    return arr[i];
}

现在,这显然是一个编译时评估:

代码语言:javascript
复制
enum { CompileTimeConstant = test1("Test", 0) };

您的例子可能是这样,但这是一个优化器/QoI问题:

代码语言:javascript
复制
char MayBeCompileTimeConstant = test1("Test", 0);

这个例子显然不是,但仍然要求是可评估的。

代码语言:javascript
复制
char arr[10];
int i;
std::cin >> i;
std::cin >> arr;
char b = test1(arr, i);
std::cout << "'" << arr << "'[" << i << "] = " << b << '\n';

因为test2不可能在最后一种情况下编译,所以它根本无法编译。(请注意,我并不是说代码是好的)。

票数 8
EN

Stack Overflow用户

发布于 2014-07-04 21:33:41

这里的问题是调用arr[i]会调用下标操作符operator[]这个运算符不返回一个常量表达式.

实际上,这不是constexpr的问题,而是模板参数推导的问题。非类型模板参数必须是下标运算符返回参数不是的常量表达式。

因此,编译器理所当然地抱怨arr[i]不是一个常量表达式。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24580714

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档