constexpr表达式和变量生命周期,g ++和clang不同意的例子

Pic*_*ent 10 c++ g++ c++11 clang++

考虑一下简单的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
}
Run Code Online (Sandbox Code Playgroud)

我可以成功地编译它 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.
Run Code Online (Sandbox Code Playgroud)

(nb:编译器版本.我用g ++版本5.3.1和7.2.1以及clang ++版本3.6.2和5.0.0检查了前一个语句)

我的问题: g ++或clang中哪一个是对的?问题是什么?

Pic*_*ent 9

我的解释是clang ++是对的,g ++太宽容了.

我们可以在标准https://isocpp.org/std/the-standard中找到一个接近的例子([expr.const]部分,第126页)(可以下载草稿,注意大PDF!).

constexpr int g(int k) { 
    constexpr int x = incr(k); 

    return x; 
}
Run Code Online (Sandbox Code Playgroud)

在那里解释说:

错误:incr(k)不是核心常量表达式,因为k的生命周期开始于表达式incr(k)之外

这正是use_size()函数与foo参数发生的情况,即使该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); }
Run Code Online (Sandbox Code Playgroud)