Fra*_*une 12 c++ linker templates inline specialization
我正在研究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
}
Run Code Online (Sandbox Code Playgroud)
预计,此代码不会链接,因为它foo<double>()有多个定义,因为它在bar.cpp中实例化一次,在main.cpp中实例化一次(通过专门化).如果这个程序将链接,那么我们会期望bar()并且main()将使用不同的实例,foo()这样最终我们将得到x == 1和y == 2.
让我们通过声明foo<double>()as 的特化来修复链接错误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
}
Run Code Online (Sandbox Code Playgroud)
我们现在有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
}
Run Code Online (Sandbox Code Playgroud)
这段代码现在正确链接,当我们运行它时,我们得到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
}
Run Code Online (Sandbox Code Playgroud)
这种情况实际上并不令人惊讶:main.cpp中foo<double>()不再实例化特殊化(尽管声明仍然存在),因此唯一的实例化是bar.cpp中的实例化.
Mat*_* M. 14
你实际上是在违反C++规则(强调我的):
14.7.3 [temp.expl.spec]:
6 /如果一个模板,一个成员模板或一个类模板的成员被明确地专门化,那么该特化应该在第一次使用该特化之前声明,这将导致隐式实例化发生,在每个翻译单元中使用发生; 无需诊断.如果程序没有提供显式特化的定义,并且特殊化的使用方式会导致隐式实例化或成员是虚拟成员函数,则程序格式错误,无需诊断.永远不会为已声明但未定义的显式特化生成隐式实例化.[ 例如:
class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v) {
sort(v); // use primary template
// sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialization
// after use of primary template
template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
template<class T> struct A {
enum E : T;
enum class S : T;
};
template<> enum A<int>::E : int { eint }; // OK
template<> enum class A<int>::S : int { sint }; // OK
template<class T> enum A<T>::E : T { eT };
template<class T> enum class A<T>::S : T { sT };
template<> enum A<char>::E : int { echar }; // ill-formed,
// A<char>::E was instantiated
// when A<char> was instantiated
template<> enum class A<char>::S : int { schar }; // OK
Run Code Online (Sandbox Code Playgroud)
- 结束例子 ]