constexpr函数与未使用的引用参数 - gcc vs clang

Vit*_*meo 8 c++ templates language-lawyer constexpr c++17

请考虑以下代码:

template <int N, typename T> void f(T) { }

template <typename T> 
constexpr int k(T&) { return 0; }

int main() 
{
    constexpr auto i = 1;
    f<k(i)>([&i]
    {
         f<k(i)>(0); 
    });
}
Run Code Online (Sandbox Code Playgroud)

clang++ (主干)编译它.g++ (trunk)因以下错误而失败:

<source>: In lambda function:

<source>:11:19: error: no matching function for call to 'f<k<const int>((* & i))>(int)'
11  |          f<k(i)>(0);
    |                   ^

<source>:1:35: note: candidate: 'template<int N, class T> void f(T)'
    1 | template <int N, typename T> void f(T) { }
      |                                   ^

<source>:1:35: note:   template argument deduction/substitution failed:

<source>:11:19: error: '__closure' is not a constant expression
11  |          f<k(i)>(0);
    |                   ^

<source>:11:13: note: in template argument for type 'int'
11  |          f<k(i)>(0);
    |            ~^~~
Run Code Online (Sandbox Code Playgroud)

godbolt.org上的实例


改变k(T&)k(T)解决问题.在我看来,问题与引用参数不是常量表达式但不用作其一部分的事实有关k.

这里的编译器是正确的?

xsk*_*xzr 6

GCC在这里是正确的.

根据[expr.const]/4:

表达式e是核心常量表达式,除非按照e抽象机器的规则评估以下表达式之一:

  • ...
  • lambda表达式中,对一个变量的引用,该变量具有在lambda表达式之外定义的自动存储持续时间,其中引用将是odr-use; ...
  • ...

k(i)i因此,odr-uses k(i)不是lambda表达式中的常量表达式,因此该代码是不正确的.