不使用特化语法实现模板类方法针对不同类型有不同实现,这是否是有效的C++代码?

14

我正在审查同事的代码,并发现了以下内容:

头文件:

template<class T>
class MyClass
{
  void Execute();
}

Cpp文件:

void MyClass<int>::Execute()
{
  // something
}

void MyClass<string>::Execute()
{
  // something else
}

这段代码针对函数进行了特化,但没有使用模板特化语法。我猜它能正常工作,但是这样合法吗?


是的。Visual Studio 2010。 - Scott Langham
对于问题标题中的任何不明确之处,我们深表歉意。 - Scott Langham
注意: 如果你这样专门化一个成员函数,你将无法再专门化主模板(这可能是个问题,也可能不是,但你会阻止类模板的所有未来专门化)。 - David Rodríguez - dribeas
4个回答

8

是的,对于模板类来说,专门化方法是完全有效的。

但是你的语法是错误的,应该是:(抱歉,刚开始没有看到你缺少了template<>。我假设它在那里并认为你是在问成员函数专门化。)

template<>
void MyClass<int>::Execute()
{
  // something
}
template<>
void MyClass<string>::Execute()
{
  // something else
}

您只需要在头文件中声明这些函数。如果您还要在头文件中实现它们,您将需要标记它们为inline以防止多重定义。

调用方法时,将调用最适合该调用的版本。否则,将使用默认版本。

在您的情况下,如果您专门使用类X来特化模板并尝试调用Execute,则会出现链接器错误,因为您没有提供默认实现,也没有提供XExecute的特化。


1
我认为你误解了问题,或者是我误解了。我认为@ScottLangham在问为什么在定义之前没有template<>,这样做完全有效吗? - Kiril Kirov
我认为这不是你所说的“专业化”。这只是“提供定义”。 - Kerrek SB
@KirilKirov 我错过了那个(没有看到缺少的 template<>)。在这种情况下,它是非法的。 - Luchian Grigore
1
在您进行编辑之后,仍然需要强调在主模板定义中是否有定义的区别——一个是可以的,另一个则违反了ODR。 - Kerrek SB
@KerrekSB,这是一种专业化。至少在B.S. in D&E中被称为这样(他解释说关键字“specialize”或“specialise”已经被考虑并被拒绝,因此当时不需要前缀)。 - AProgrammer
@AProgrammer:我知道,我知道。在标准语义上它是专业化的,但在口语上不是这样说的,我想。 - Kerrek SB

5
这个问题已经被回答了,但是我想指出三种情况之间的细微差别。

情况一:专业化

标题:

template <typename T> struct Foo
{
    void f() { /* stuff */ }
};

template <> void Foo<int>::f();

源代码:

template <> void Foo<int>::f() { /* ... */ }

在这种情况下,可以为任何T调用Foo::f()。一般情况的定义是从模板自动生成的;而Foo::f()的定义则是所提供的那个。在头文件中进行特化会提醒每个使用它的翻译单元需要查找一个单独的符号,而不是使用模板。
template <typename T> struct Foo
{
    void f();
};

来源:

template <> void Foo<int>::f() { /* ... */ }

在这种情况下,只能使用Foo<int>::f();其他所有的都会导致链接错误。由于模板中没有该函数的定义,每次使用模板都会导致新的符号被生成,而只有Foo<int>::f()在所示的翻译单元中提供。

案例三:明显的错误

头文件:

template <typename T> struct Foo
{
    void f() { /* stuff */ }
};

source:

template <> void Foo<int>::f() { /* ... */ }

这是一种违反单一定义规则的行为,因为现在存在多个Foo<int>::f()的定义。


4

这是显式特化的旧语法。但我惊讶于您正在使用仍然接受它的编译器(g++在4.0左右停止支持)。为了符合标准,您需要在特化前加上template <>前缀。


2

回答标题中的问题:绝对可以。在特化中拥有一组完全不相关的成员也是有效的。

回答代码中的问题:我认为这似乎是编译器的一个错误。需要使用 template <>


抱歉...我标题缩写过度了。 - Scott Langham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接