具有未使用的引用参数的constexpr函数– gcc vs clang

时间:2018-12-30 13:29:06

标签: c++ templates language-lawyer c++17 constexpr

考虑以下代码:

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); 
    });
}

clang++ (树干)对其进行编译。 g++ (树干)失败,并显示以下错误:

<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);
    |            ~^~~

live example on godbolt.org


k(T&)更改为k(T)可解决此问题。在我看来,该问题与引用参数不是常量表达式,但没有用作k的一部分有关。

什么编译器在这里正确?

3 个答案:

答案 0 :(得分:6)

这里的GCC是正确的。

根据[expr.const]/4

  

表达式e是核心常量表达式,除非求值   遵循抽象机规则的e的   以下表达式之一:

     
      
  • ...
  •   
  • lambda-expression 中,对变量的引用,该变量具有在 lambda-expression 之外定义的自动存储持续时间,   凡该提述将作单一用途; ...
  •   
  • ...
  •   

k(i)会使用i,因此k(i)在lambda表达式中不是常量表达式,因此该代码格式错误。

答案 1 :(得分:0)

出现在lambda表达式复合语句中但不在表达式外部的表达式k(i)发出错误。这是一个GCC错误。根据{{​​3}}

  

lambda表达式的复合语句中的 id-expression 是对引用捕获的引用的odr-use的odr-使用,指的是捕获的引用绑定到的实体,而不是捕获的参考。

因此,lambda外部的k(i)与lambda外部的k(i)是相同的表达式,因此GCC没有理由针对第二个表达式而不是第一个表达式发出错误。

答案 2 :(得分:-1)

编译时出现0个错误。

我使用了变量result_k = k(i);来绕过此错误。

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

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

int main() {
    constexpr auto i = 1;
    const int result_k=k(i);
    f<result_k>([&i]{ f<result_k>(0);});
}