gpt4 book ai didi

C++ 链接和模板特化

转载 作者:IT老高 更新时间:2023-10-28 23:17:09 25 4
gpt4 key购买 nike

我正在研究 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 中的实例。

最佳答案

您实际上在这里违反了 C++ 规则(强调我的):

14.7.3 [temp.expl.spec]:

6/ If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the programdoes not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. [ Example:

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

end example ]

关于C++ 链接和模板特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7190424/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com