функция constexpr с неиспользованным ссылочным аргументом - gcc vs clang - PullRequest
0 голосов
/ 30 декабря 2018

Рассмотрим следующий код:

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

живой пример на godbolt.org


Изменение k(T&) на k(T) решает проблему.Мне кажется, что проблема связана с тем, что ссылочный аргумент не является константным выражением , но он не используется как часть k.

Какой компиляторздесь правильно?

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Скомпилировано с 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);});
}
0 голосов
/ 30 декабря 2018

GCC здесь верен.

Согласно [expr.const] / 4 :

Выражение e является выражением основной константы, если толькооценка e, следуя правилам абстрактной машины, оценила бы одно из следующих выражений:

  • ...
  • в лямбда-выражении , ссылка на [...] переменную с автоматической продолжительностью хранения, определенной вне этого лямбда-выражения , где ссылка будет использовать odr;...
  • ...

k(i) odr использует i, таким образом, k(i) не является константным выражением в лямбда-выражении, поэтому этот кодплохо сформирован.

0 голосов
/ 30 декабря 2018

Ошибка выдается для выражения k(i), которое появляется в составных выражениях лямбда-выражения, но не за его пределами.Это ошибка GCC.Согласно [expr.prim.lambda.capture] / 11

id-выражение в составном выражении лямбда-выражения, котороеodr-использование ссылки, захваченной ссылкой , относится к объекту, к которому привязанная ссылка привязана , а не к захваченной ссылке.

То есть k(i) вне лямбдытакое же выражение, что и k(i) вне лямбды, поэтому у GCC нет причин выдавать ошибку для второго выражения, но не для первого.

...