Pergunta

Considere o seguinte código:

#include <stdio.h>

namespace Foo {
  template <typename T>
  void foo(T *, int) { puts("T"); }

  template <typename T>
  struct foo_fun {
    static void fun() { foo((T *)0, 0); };
  };
}

namespace Foo {
  void foo(int *, int) { puts("int"); }
}

using namespace Foo;

int main() {
  foo_fun<int> fun;
  fun.fun();
}

Qual é a saída esperada? "T" ou int?

Um compilador (GCC 4.0.1 da saída Xcode 3.1.2) da Apple "int", dois outros compiladores (GCC 4.1.2 e 4.1.3) saída "T".

Se eu mover foo (int *, int) declaração/definição antes da versão Foo (t *, int), toda saída "int". A ordem de sobrecarga/especialização neste caso é definida pelo padrão atual?

Foi útil?

Solução

O segundo void foo(... é uma sobrecarga (e não uma especialização) que não é visível na definição de foo_fun::fun Portanto, não será encontrado no contexto da definição de modelo. Porque T* é um tipo dependente, resolução de foo na expressão foo((T*)0, 0) será adiado até que o tempo de instanciação do modelo e o contexto da instanciação também sejam considerados. No entanto, 14.6.4.2 do padrão diz que se o nome da função for um ID não qualificado mas não um modelo-id Então, para a pesquisa não ADL, apenas as funções visíveis no ponto de definição do modelo são consideradas. Não há argumentos de função do Foo namespace para que nenhuma pesquisa dependente de argumento ocorra, portanto a versão de modelo de foo é chamado e não a sobrecarga que não é de templos.

Muito obrigado a Litb pelas correções dessa resposta.

Se você fez uma especialização como abaixo, como as especializações são escolhidas no tempo de instanciação do modelo, a especialização pode ser chamada desde que a especialização relevante seja visível no ponto em que o modelo de função é instanciado pela primeira vez para int.

namespace Foo {
    template<>
    void foo<int>(int *, int) { puts("int"); }
}

Capítulo 14 do padrão atual, mas não é muito legível :)

Editar: se eu tivesse que escolher a parte mais relevante do padrão, provavelmente seria 14.6 [temp.res] parágrafo 9. (ligeiramente abreviado) se um nome não depender de um Parâmetro de modelo, uma declaração para esse nome estará em escopo no ponto em que o nome aparece na definição do modelo; O nome está vinculado à declaração encontrada nesse ponto e essa ligação não é afetada por declarações visíveis no ponto de instanciação.

Editar, editar: mas você também precisa levar em consideração 14.6.4.2 [temp.dep.candidate]. É muito difícil e perigoso tentar fazer referência ao padrão devido a todas as interdependências, essa resposta é um exemplo.

Outras dicas

Como regra geral, de duas versões de um compilador, o posterior é mais provável que seja mais padrão.

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