这可以合法地用C ++完成吗?

时间:2011-05-03 20:32:56

标签: c++ templates language-specifications one-definition-rule

注意:the following code is illegal, but a conforming compiler is not required to reject it(有些人没有)。

在我正在使用的库中,我有Foo的模板函数声明和Barfoobar.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包含的。但是(因为我希望我不需要解释)这是一个非首发。

3 个答案:

答案 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的特化,留在目标文件中,但当时没有任何其他内容。链接器运行时,它会找到所需的一切。

更新
所以我不知道为什么这是非法的,但由于某种原因它似乎确实编译并运行。