web-dev-qa-db-fra.com

fonction constexpr avec un argument de référence non utilisé - gcc vs clang

Considérons le code suivant:

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++(trunk)} _ le compile. g++(trunk) _ échoue avec l'erreur suivante:

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

exemple live sur godbolt.org


Remplacer k(T&) par k(T) résout le problème. Il me semble que le problème est lié au fait que l'argument de référence n'est pas un expression constante, mais qu'il n'est pas utilisé dans le cadre de k.

Quel compilateur est correct ici?

7
Vittorio Romeo

GCC a raison ici.

Selon [expr.const]/4 :

Une expression e est une expression constante de base sauf si l'évaluation de e, suivant les règles de la machine abstraite, évaluerait une des expressions suivantes:

  • ...
  • dans lambda-expression, référence à une variable [...] avec durée de stockage automatique définie en dehors de lambda-expression, où la référence serait une odr-use; ...
  • ...

k(i) odr-utilise i donc k(i) n'est pas une expression constante dans l'expression lambda, donc ce code est mal formé.

5
xskxzr

L'erreur est émise pour l'expression k(i) qui apparaît dans les instructions composées d'expression lambda mais pas en dehors de celle-ci. C'est un bug de GCC. Selon [expr.prim.lambda.capture]/11

Une expression id-expression dans l'instruction composée d'une expression-lambda qui est une utilisation odr d'une référence capturée par la référence fait référence à l'entité à laquelle la référence capturée est liée et non à la capture référence.

Donc k(i) en dehors du lambda est la même expression que k(i) en dehors du lambda, il n’ya donc aucune raison pour que GCC émette une erreur pour la deuxième expression mais pas pour la première.

0
Oliv