注意:the following code is illegal, but a conforming compiler is not required to reject it(有些人没有)。
在我正在使用的库中,我有Foo
的模板函数声明和Bar
中foobar.h
的模板函数定义:
template<class C> int Foo();
template<class C> int Bar() {
return Something( Foo<C>() );
}
意图是其他代码可以像这样使用它:
#include "foobar.h"
int main() {
Bar<MyClass>();
return 0;
}
// Ideally, the usage (above) and the definition (below)
// would/could be in different translation units.
template<> int Foo<MyClass>() { return 5; }
问题: 有没有办法让这项工作也合法?
问题是(如果我理解正确的话),尽管进行了编译,但这在技术上是非法的:它违反了ODR,因为显式专业化和Bar<MyClass>
的用法都算作定义,尽管在使用案例中没有任何机构可以使用。
我想使用这种模式来参数化Foo
的原因是,作为我需要遵循的样式指南的结果,唯一的方法是确保在{的定义之前词汇包含任何内容{1}}是由Bar
包含的。但是(因为我希望我不需要解释)这是一个非首发。
答案 0 :(得分:3)
有没有办法让这项工作也合法?
是的,在使用之前声明专业化。只需在您的文件中交换specialization和main的顺序,就可以在您提供的示例中执行此操作。但是,在该示例中,您仍然必须确保没有其他TU使用该专业而不声明它。
通常,这些特化应该在标题中声明。
在您的示例的范围内(即没有根本性的变化),没有其他方法可以使这项工作。
答案 1 :(得分:1)
这是不合法的,因为无法专门化模板功能。
你可以这样做:
template< typename T >
struct foo
{
static int doSomething() {return 0;}
};
template< >
struct foo<int>
{
static int doSomething() {return 5;}
};
答案 2 :(得分:1)
这将编译链接并运行VS2008和gcc 4.5.2:
template<class C> int Foo();
int Something(int i ){ return i; }
template<class C> int Bar() {
return Something( Foo<C>() );
}
class MyClass{};
class FooClass{};
// Update:
// Declaration of a specialisation.
template<> int Foo<MyClass>();
int Zoo(){
return Something( Foo<MyClass>() );
}
#include <iostream>
int main() {
std::cout << Bar<MyClass>() << std::endl;
std::cout << Zoo() << std::endl;
std::cout << Bar<FooClass>() << std::endl;
return 0;
}
// Definitions of specialisations.
template<> int Foo<MyClass>() { return 5; }
template<> int Foo<FooClass>() { return 6; }
输出结果为:
5
5
6
这样做的原因是,尽管只是声明了,但模板函数 Foo
确实有两个必需的定义可供链接器使用。
在编译时,当编译器看到main
的定义时,它可以创建Bar
的特化,但不能创建Foo
的特化。在这种情况下,它只是创建对Foo<MyClass>()
和Foo<FooClass>()
的函数调用
稍后编译器会找到它编译的Foo
的特化,留在目标文件中,但当时没有任何其他内容。链接器运行时,它会找到所需的一切。
的更新强>
所以我不知道为什么这是非法的,但由于某种原因它似乎确实编译并运行。