Pergunta

Por favor, considere o seguinte código:

template<typename T>
char (&f(T[1]))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

Eu esperava que fazer SFINAE e escolhendo a segunda sobrecarga, uma vez que a substituição de T em rendimentos T[1]

 void [1]()

O que é um tipo inválido, é claro. Ajuste de tipos de parâmetros (array-> ponteiro) é feito após substituindo parâmetros do modelo para os parâmetros de função e verificação de tipos resultantes válidos como 14.8.2 [temp.deduct] descreve.

Mas ambos comeau e GCC não compilar o acima. Ambos com diferentes diagnósticos.

Comeau diz:

"ComeauTest.c", linha 2: erro: conjunto de funções não é permitido char (&f(T[1]))[1];

GCC diz (versão 4.3.3):

erro: proíbe ISO C ++ matriz de tamanho zero c

Significado, GCC não deixa de substituto, mas escolhe a primeira sobrecarga de f, retornando um sizeof de 1, em vez de não substituí-lo na frente como Comeau.

O compilador é certo e é o meu código válido em tudo? Por favor, consulte ou citar a seção padrão adequado na sua resposta. Obrigado!


Atualizar : O padrão em si contém um exemplo tal na lista de 14.8.2/2. Eu não sei por que eu negligenciado pela primeira vez:

template <class T> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array

Embora o exemplo é apenas informativo, ele mostra a intenção de todos os parágrafos misteriosas e parece mostrar o código acima deve funcionar e rejeitar o primeiro sobrecarga.

Foi útil?

Solução

Uma pequena nota, embora muito raro, eu encontrei algumas ocasiões onde eu Acreditamos que o compilador Comeau tem errado - embora, estes ocasiões são tão raros que é sempre vale o dobro e triplo verificar suas hipóteses!

Talvez eu tenha uma razão para o comportamento de g ++. Eu não tenho certeza sua especificado exatamente quando tipos de parâmetros são ajustados:

Considere o seguinte:

template<typename T>
struct A
{
  void bar (T[10]);
};

template<typename T>
void A<T>::bar (T*)
{
}

A definição de 'bar' é legal, como "T [10]" decai para "T *". eu faço não vejo nada na norma que proíbe o compilador realizando os ajustes de 8.3.5 contra a declaração modelo, e também melhora o desempenho quando se trata de correspondência de sobrecarga.

Aplicando isso ao seu exemplo, g ++ pode ser tratando-o como:

template<typename T>
char (&f( T* ))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

No exemplo acima, o parâmetro substituído é um ponteiro legal para função, em vez de uma variedade de funções.

Assim, a pergunta para mim é - é se há algo que prohibts os ajustes para os parâmetros de função (8.3.5) duas vezes?

Pessoalmente, eu acho que faz sentido para permitir que os ajustes para acontecer duas vezes uma vez que de outra forma que complica a correspondência de modelo de função sobrecargas

Em conclusão, eu acho que é válido para g ++ para selecionar a primeira sobrecarga baseado em como ele treates parâmetros de matriz em decomposição, e Comeau está errado não ter uma falha dedução para a gama de funções.

É claro que isso significa que agora (se Comeau foi fixado), em seguida, cada compilador iria escolher uma sobrecarga diferente e ainda estaria normas compatível! : (

EDIT:

Apenas para ilustrar meu ponto, considere o seguinte código:

template <typename T> void foo ( T * );
template <typename T> void foo ( T * const );
template <typename T> void foo ( T [] );
template <typename T> void foo ( T [10] );
template <typename T> void foo ( T [100] );

void bar () 
{
  foo < void() > ( 0 );
}

Aqui, foo tenha sido declarado e declarado novamente várias vezes. Que declaração, e assim que tipo de parâmetro, deve o compilador aplicar as regras listadas na 14.8.2?

Meu ponto é que o padrão não diz nada sobre o acima. Eu também iria tão longe a ponto de dizer que qualquer fraseio neste teria que deixá-lo como qualquer um "indefinido" ou "implementação definido" comportamento.

Outras dicas

Surpreendentemente o suficiente - isso não funciona no VS2008. Eu não acho que isso é necessariamente prova para ele ser o comportamento correto ou não embora ...

Visual Studio é interpretting

char (&f(T[1]))[1];

como uma função que leva uma matriz de tamanho 1 de T, e retorna uma referência a um conjunto de caracteres de tamanho 1.

Vou tentar descrever o processo de template argumento dedução como eu entendo da leitura do padrão.

  1. argumentos explícitos de modelo são verificados como descrito em 14.8.2 / 2.
  2. A assinatura da função resultante é ajustado de acordo com 8.3.5 (isto é, a matriz de decaimento ponteiro é executada).
  3. argumentos de modelo implícitos são deduzidos como por 14.8.2.1 (isto é executado em uma assinatura parcialmente substituído a partir do passo 2).

A dedução para a primeira sobrecarga falha no passo 1, a resolução de sobrecarga, portanto, retorna o segundo sobrecarga. Eu não acredito que o programa está mal-formado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top