Especializações de vinculação e modelo em C ++
Estou estudando o comportamento do vinculador C ++ em relação às especializações de modelo. Estou usando o Microsoft Visual C ++ 2010 para esses experimentos. Não sei se o comportamento é o mesmo com outras cadeias de ferramentas (por exemplo, gcc).
Aqui está o primeiro trecho de código:
// bar.cpp
template <typename T> int foo() { return 1; }
int bar() { return foo<double>(); }
// main.cpp
template <typename T> int foo() { return 1; }
template <> int foo<double>() { return 2; }
int bar();
int main()
{
const int x = bar();
const int y = foo<double>(); // doesn't link
}
Esse código não é vinculado porquefoo<double>()
possui várias definições, pois é instanciado uma vez em bar.cpp e uma vez em main.cpp (via especialização). Esperaríamos então,se este programa vincular, quebar()
emain()
usaria instanciações distintas defoo()
tal que no final teríamos x == 1 e y == 2.
Vamos corrigir o erro de link declarando a especialização defoo<double>()
Comostatic
:
// bar.cpp
template <typename T> int foo() { return 1; }
int bar() { return foo<double>(); }
// main.cpp
template <typename T> int foo() { return 1; }
template <> static int foo<double>() { return 2; } // note: static
int bar();
int main()
{
const int x = bar(); // x == 1
const int y = foo<double>(); // y == 2
}
Temos agora x == 1 e y == 2, como esperávamos. (Nota: nósdev use ostatic
palavra-chave aqui: um espaço para nome anônimo não funciona, pois não podemos especializar uma função de modelo em um espaço para nome diferente da declaração.)
Agora, o uso dostatic
palavra-chave @ é pouco intuitiva. Normalmente, a especializaçãofoo<double>()
residiria em algum lugar de um arquivo de cabeçalho e, portanto, seria marcado como embutido, como no seguinte snippet:
// bar.cpp
template <typename T> int foo() { return 1; }
int bar() { return foo<double>(); }
// main.cpp
template <typename T> int foo() { return 1; }
template <> inline int foo<double>() { return 2; } // note: inline
int bar();
int main()
{
const int x = bar(); // x == 2
const int y = foo<double>(); // y == 2
}
Este código agora está vinculado corretamente e, quando o executamos, obtemos x == 2 ey == 2.Este é o pouco que acho surpreendente: por que existe uma única definição defoo<double>()
? Qual é o significado deinline
neste código?
Um último fragmento:
// bar.cpp
template <typename T> int foo() { return 1; }
int bar() { return foo<double>(); }
// main.cpp
template <typename T> int foo() { return 1; }
template <> inline int foo<double>() { return 2; } // note: inline
int bar();
int main()
{
const int x = bar(); // x == 1
// const int y = foo<double>(); // note: commented out
}
Este caso não é realmente surpreendente: a especialização defoo<double>()
não é mais instanciado em main.cpp (embora a declaração ainda esteja lá), a única instancia restante é a em bar.cpp.