constexpr 表达式和变量生存期,G++ 和 Clang 不同意的一个例子
constexpr expression and variable lifetime, an example where g++ and clang disagree
考虑简单的C++11代码:
template<int N>
struct Foo {};
template <int N>
constexpr int size(const Foo<N>&) { return N; }
template <int N>
void use_size(const Foo<N>& foo) { constexpr int n = size(foo); }
int main()
{
Foo<5> foo;
constexpr int x = size(foo); // works with gcc and clang
// _but_
use_size(foo); // the same statement in the use_size()
// function _only_ works for gcc
}
我可以用g++ -std=c++11 foo.cpp
成功编译它
但是如果我使用 clang++,clang++ -std=c++11 foo.cpp
我得到
foo.cpp:15:28: error: constexpr variable 'n' must be initialized by a constant expression
void use_size(const Foo<N>& foo) { constexpr int n = size(foo); }
~~~~~^~~~
foo.cpp:23:5: note: in instantiation of function template specialization 'use_size<5>' requested here
use_size(foo); // the same statement in the use_size()
^
1 error generated.
(注意:编译器版本。我已经使用 g++ 版本 5.3.1 和 7.2.1 以及 clang++ 版本 3.6.2 和 5.0.0 检查了前面的语句(
我的问题:g++ 或 clang 哪个是对的?问题出在哪里?
我的解释是 clang++ 是对的,而 g++ 太宽松了。
我们可以在标准 https://isocpp.org/std/the-standard 中找到一个接近的例子([expr.const]部分,第126页((草稿可以下载,注意大PDF!
constexpr int g(int k) {
constexpr int x = incr(k);
return x;
}
其中解释为:
错误:incr(k( 不是核心常量表达式,因为 K的寿命始于表达式incr(k(之外
这正是使用 foo
参数的 use_size()
函数中发生的情况,即使 size()
函数仅使用 N
模板参数也是如此。
template <int N>
constexpr int size(const Foo<N>&) { return N; }
template <int N>
void use_size(const Foo<N>& foo) { constexpr int n = size(foo); }
我预计Clang在这种情况下是错误的。它应该将您的函数调用评估为常量表达式,这仅仅是因为您只使用模板参数,而不是对象本身。由于您不在 constexpr
函数中使用该对象,因此应该不会禁止编译时计算。
但是,标准中有一条规则,即在常量表达式(如引用(之前开始其生命周期的对象不能用作constexpr。
在这种情况下,有一个简单的修复程序。我认为它不喜欢参考:
template <int N> // pass by value, clang is happy
void use_size(Foo<N> foo) { constexpr int n = size(foo); }
这是一个活生生的例子
或者,您也可以复制 foo 对象并使用该本地对象:
template <int N>
void use_size(const Foo<N>& foo) {
auto f = foo;
constexpr int n = size(f);
}
现场示例
相关文章:
- 我们可以访问一个不存在的联盟的成员吗
- decltype(1, t) 应该是 l 值引用吗?(编译器不同意)
- GCC/CLang不同意模板模板参数的部分特化
- 如果我注释掉换行符,为什么'string'会成为一个不合格的变量
- 找到 x^n 的所有组合,并检查它们的总和是否等于一个不包括相同数字的数字
- 我们应该在使用 std::bind 应用之前检查一个不为空的函数吗?
- 类中的一个变量显示,但另一个不显示
- 为什么我的数组输出一个不在其中的元素
- 将积分类型的数组作为另一个不相关的积分类型的阵列进行访问的安全且符合标准的方法
- 模板函数,其中一个参数需要专门化,而另一个不需要
- RXCPP:创建一个不关心可观察量输入类型的扩展
- l值引用对象上的Constexpr成员函数:Clang和gcc不同意
- 没有一个不是用NewObject,NewNamedObject或ConstructObject构建的,但它是
- 为什么这C++只在编译器上编码一个不明确的方法调用Microsoft?
- 除了说明符神秘地破坏编译(Clang,GCC不同意)
- 有没有办法创建一个不改变程序中参数的函数
- [expr.unary.op]/9 似乎暗示"运算符!()' 不能应用于下面的类型 A.但编译器不同意这一点
- C ++尝试访问映射中的元素会给我一个不匹配的函数调用错误
- constexpr 表达式和变量生存期,G++ 和 Clang 不同意的一个例子
- 内部阶级、皮条客和一个朋友阶级——不同意的编译器