Perplexando o comportamento do pacote de parâmetros non-trailing

9

Eu me deparei com um comportamento interessante da função template variadica. Alguém pode apontar as regras relevantes no padrão que define isso?

GCC , ICC e MSVC compilam o seguinte código com sucesso (Clang não, mas eu entendo que isso se deve a erros do compilador).

template<class A, class... Bs, class C>
void foo(A, Bs..., C) { }

int main()
{
    foo<int, int, int, int>(1, 2, 3, 4, 5);
}

Nesta chamada para foo , os argumentos de modelo são fornecidos para A e Bs , então C é deduzido como int .

No entanto, se simplesmente invertermos os dois últimos parâmetros de modelo:

template<class A, class C, class... Bs>
void foo(A, Bs..., C) { }

Em seguida, todos três compiladores causam erros. Aqui está o do GCC:

main.cpp: In function 'int main()':
main.cpp:8:42: error: no matching function for call to 'foo(int, int, int, int, int)'
     foo<int, int, int, int>(1, 2, 3, 4, 5);
                                          ^
main.cpp:4:6: note: candidate: template<class A, class C, class ... Bs> void foo(A, Bs ..., C)
 void foo(A, Bs..., C) { }
      ^~~
main.cpp:4:6: note:   template argument deduction/substitution failed:
main.cpp:8:42: note:   candidate expects 4 arguments, 5 provided
     foo<int, int, int, int>(1, 2, 3, 4, 5);
                                      ^

Para tornar as coisas mais interessantes, chamar com apenas quatro argumentos é inválido para o primeiro foo e válido para o segundo.

Parece que na primeira versão de foo , C deve ser deduzida, enquanto que na segunda, C deve ser explicitamente fornecida. / p>

Quais regras do padrão definem esse comportamento?

    
por TartanLlama 08.08.2016 в 12:56
fonte

1 resposta

2

Como é frequentemente o caso, a resposta veio a mim algumas horas depois que eu postei a pergunta.

Considere as duas versões de foo :

template<class A, class... Bs, class C>
void foo1(A, Bs..., C) { }

template<class A, class C, class... Bs>
void foo2(A, Bs..., C) { }

e a seguinte chamada (assumindo foo é foo1 ou foo2 ):

foo<int,int,int,int>(1,2,3,4,5);

No caso de foo1 , os parâmetros do modelo são escolhidos da seguinte forma:

A = int (explicitly provided)
Bs = {int,int,int} (explicitly provided)
C = int (deduced)

Mas no caso de foo2 eles se parecem com isso:

A = int (explicitly provided)
C = int (explicitly provided)
Bs = {int,int} (explicitly provided)

Bs está em um contexto não deduzido ( [temp.deduct.type]/5.7 ), portanto, nenhum outro argumento de função pode ser usado para estender o pacote. Como tal, foo2 deve ter todos os argumentos de modelo explicitamente fornecidos.

    
por TartanLlama 08.08.2016 / 17:44
fonte