首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在constexpr clang诉GCC中的非-constexpr变量

在constexpr clang诉GCC中的非-constexpr变量
EN

Stack Overflow用户
提问于 2018-02-16 12:14:51
回答 1查看 538关注 0票数 4
代码语言:javascript
复制
struct A{
    constexpr operator bool()const{ return true; }
};

int main(){
    auto f = [](auto v){ if constexpr(v){} };
    A a;
    f(a);
}

clang 6接受“守则”,GCC 8拒绝“守则”,并:

代码语言:javascript
复制
$ g++ -std=c++17 main.cpp
main.cpp: In lambda function:
main.cpp:6:37: error: 'v' is not a constant expression
  auto f = [](auto v){ if constexpr(v){} };
                                     ^

谁是正确的,为什么?

当我在每个引用中接受参数时,两种方法都拒绝代码:

代码语言:javascript
复制
struct A{
    constexpr operator bool()const{ return true; }
};

int main(){
    auto f = [](auto& v){ if constexpr(v){} };
    constexpr A a;
    f(a);
}

用clang 6编译:

代码语言:javascript
复制
$ clang++ -std=c++17 main.cpp
main.cpp:6:40: error: constexpr if condition is not a constant expression
    auto f = [](auto& v){ if constexpr(v){} };
                                       ^
main.cpp:8:6: note: in instantiation of function template specialization 
    'main()::(anonymous class)::operator()<const A>' requested here
    f(a);
     ^
1 error generated.

当我将参数复制到局部变量中时,双方都接受以下代码:

代码语言:javascript
复制
struct A{
    constexpr operator bool()const{ return true; }
};

int main(){
    auto f = [](auto v){ auto x = v; if constexpr(x){} };
    A a;
    f(a);
}

编辑:我确信第二和第三种情况将由两个编译器正确处理。不过,我不知道规矩是什么。

在第一种情况下,我怀疑clang是对的,因为这种情况类似于第二种情况。我想知道,在第一种情况下,clang或GCC是否是正确的,在第二种情况下,哪些规则使非恒定变量v无效,而在第三种情况下,x是有效的。

编辑2:第一个问题现在很清楚:bug.cgi?id=84421

clang是对的,GCC 7也接受了这个代码。这个错误将在GCC 8的最终版本中修复。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-17 01:19:22

Clang在任何情况下都是正确的。完全披露:我是一个Clang开发人员

在所有情况下,问题都归结为:我们可以在常量表达式中调用v上的v成员函数吗?

要回答这个问题,我们需要看看expr.constp2,它说:

表达式e是一个核心常量表达式,除非e的计算遵循抽象机器(6.8.1)的规则计算下列表达式之一:

  • ..。
  • 引用类型的变量或数据成员的id-表达式,除非引用具有前面的初始化和。
    • 它用常量表达式初始化,或者
    • 其寿命在e评价范围内开始;

  • ..。

其他任何规则都不禁止你举任何例子。特别是,如果局部变量不是引用类型,则允许在常量表达式中命名它们。(不允许对它们执行lvalue到rvalue的转换-也就是说,读取它们的值--除非它们的值已知(例如,因为它们是constexpr),并且不允许您最终引用这样一个变量的地址,但是您可以命名它们。)

对于引用类型的实体,规则不同的原因是,仅仅命名引用类型的实体就会立即解析引用,即使您没有对结果做任何事情,解析引用也需要知道它绑定到什么。

所以:第一个例子是有效的。*this成员函数的constexpr值绑定到局部变量a。我们不知道那是什么对象并不重要,因为评估并不在乎。

第二个示例(其中v是引用类型的)格式不正确。仅仅命名v需要将其解析到它绑定到的对象,这不能作为常量表达式计算的一部分来完成,因为我们不知道它最终会被绑定到什么。重要的是,后面的评估步骤不会使用结果对象;引用在命名时立即被解析。

第三个示例的有效原因与第一个示例相同。值得注意的是,即使您将v更改为引用类型,第三个示例仍然有效:

代码语言:javascript
复制
auto f = [](auto &v) { auto x = v; if constexpr (x) {} };
A a;
f(a);

..。因为x再次是一个局部变量,我们可以在常量表达式中命名它。

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

https://stackoverflow.com/questions/48826555

复制
相关文章

相似问题

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