2

注意:以下代码是非法的,但不需要符合要求的编译器拒绝它(有些则不需要)。

在我正在使用的库中,我有一个模板函数声明Foo和一个模板函数定义Barin 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>count 作为定义,尽管事实上没有实体可以使用用例。

我想使用此模式进行参数化的原因Foo是,由于我必须遵循样式指南,确保在定义之前以词法方式包含任何内容的唯一方法是Bar将其包含在foobar.h. 但是(出于我希望我不需要解释的原因)这不是首发。

4

3 回答 3

3

有没有办法使这项工作也合法?

是的,在使用之前声明专业化。在您提供的示例中,只需交换文件中专业化和主要的顺序即可。但是,在示例中,您仍然必须确保没有其他 TU 使用该专业化而不声明它。

通常,这些特化应在标头中声明。

在您的示例的范围内(即没有根本性的改变),没有其他方法可以使这项工作。

于 2011-05-04T16:46:53.747 回答
1

这是不合法的,因为不可能专门化模板函数。

你可以做这样的事情:

template< typename T >
struct foo
{
  static int doSomething() {return 0;}
};
template< >
struct foo<int>
{
  static int doSomething() {return 5;}
};
于 2011-05-03T20:39:36.720 回答
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,但不能创建 的特化FooFoo<MyClass>()在这种情况下,它只是创建对and的函数调用Foo<FooClass>()
稍后编译器找到Foo它编译的特化,留在目标文件中,但当时什么都不做。当链接器运行时,它会找到所需的一切。

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

于 2011-05-03T21:06:13.933 回答