Я изучаю поведение компоновщика C++ в отношении специализаций шаблонов. Я использую Microsoft Visual C++ 2010 для этих экспериментов. Я не знаю, такое ли поведение с другими наборами инструментов (например, gcc).
Вот первый фрагмент кода:
// 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
}
Как и следовало ожидать, этот код не связан, потому что foo<double>()
имеет несколько определений, поскольку он создается один раз в bar.cpp и один раз в main.cpp (через специализацию). Затем мы ожидаем, что если эта программа свяжется, что bar()
и main()
будут использовать разные экземпляры foo()
, так что в конце мы получим x == 1 и y == 2.
Давайте исправим ошибку ссылки, объявив специализацию foo<double>()
как static
:
// 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
}
Теперь у нас есть x == 1 и y == 2, как мы и ожидали. (Примечание: мы должны использовать здесь ключевое слово static
: анонимное пространство имен не подойдет, поскольку мы не можем специализировать шаблонную функцию в пространстве имен, отличном от его объявления.)
Теперь использование ключевого слова static
довольно неинтуитивно. Как правило, специализация foo<double>()
находится где-то в заголовочном файле и поэтому помечается как встроенная, как в следующем фрагменте:
// 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
}
Теперь этот код правильно компонуется, и когда мы его запускаем, мы получаем x == 2 и y == 2. Этот момент меня удивляет: почему существует единственное определение foo<double>()
? Что означает inline
в этом коде?
Последний фрагмент:
// 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
}
Этот случай на самом деле неудивителен: специализация foo<double>()
больше не реализуется в main.cpp (хотя объявление все еще там), поэтому остается только одна конкретизация в bar.cpp. эм>.
foo<double>()
(вы ничего не специализируете). Кроме того, в следующем предложении явная специализация, вероятно, должна быть просто специализацией или полной специализацией, чтобы избежать путаницы с похожим по звучанию явным воплощением (которого у вас нет). - person Kerrek SB   schedule 25.08.2011inline
используете функцию, вы обещаете, что она будет иметь одинаковое определение во всех единицах перевода. Если это правда, то вы подвергаетесь неопределенному поведению. - person Kerrek SB   schedule 25.08.2011inline
илиstatic
здесь. Параграф о специализации шаблонов не содержит специальных положений для них. - person Matthieu M.   schedule 25.08.2011extern inline
иstatic inline
:-/ - person Šimon Tóth   schedule 25.08.2011