为什么不能重载类模板?

时间:2012-08-15 12:08:43

标签: c++ templates overloading template-specialization language-lawyer

阅读this question让我想知道:是否存在禁止类模板重载的技术原因?

通过重载,我的意思是有几个模板具有相同的名称,但参数不同,例如

template <typename T>
struct Foo {};

template <typename T1, typename T2>
struct Foo {};

template <unsigned int N>
struct Foo {};

编译器设法处理重载的函数和函数模板,是不是可以将相同的技术(例如名称修改)应用于类模板?

首先,我认为这可能会在单独使用模板标识符时引起一些歧义问题,但是唯一可能发生的情况是将其作为模板模板参数传递,因此参数的类型可用于选择适当的过载:

template <template <typename> class T>
void A {};

template <template <unsigned int> class T>
void B {};

A<Foo> a; // resolves to Foo<T>
B<Foo> b; // resolves to Foo<N>

您认为此功能有用吗?是否存在一些“好的”(即技术)原因,为什么在当前的C ++中这是不可能的?

3 个答案:

答案 0 :(得分:33)

模板完整指南Amazon)中的第12.5节包含此引用:

  

您可能会合理地想知道为什么只有类模板可以部分专业化。原因主要是历史原因。   可能可以为函数模板定义相同的机制(参见第13章)。

     

在某些方面   重载函数模板的效果类似,但也有一些细微的差别。这些差异是   主要与主要模板需要的事实有关   遇到使用时查找。专业是   之后才考虑,确定应该采用哪种实施方式   用过的。

     

相反,必须带来所有重载的功能模板   通过查找它们来设置过载,它们可能来自   不同的命名空间或类。这增加了可能性   在某种程度上无意中重载了模板名称。

     

相反,它   也可以想象允许一种形式的类模板重载。   这是一个例子:

// invalid overloading of class templates
template<typename T1, typename T2> class Pair; 
template<int N1, int N2> class Pair; 
     

然而,似乎并不迫切需要   这样的机制。

此外, C ++的设计和演变Amazon)在第15.10.3节中包含此引用

  

因此,我得出结论,我们需要一种“专业化”的机制   模板。这可以通过接受一般的重载来完成   或者通过一些更具体的机制。我选择了一种特定的机制   因为我以为我主要是解决由此造成的违规行为   C中的不规则性以及因为超载的建议总是存在的   制造了抗议的嚎叫。我试图保持谨慎   保守; 我现在认为这是一个错误。专业化   最初定义的是一种限制和异常形式的重载   与其他语言不符合。

大胆强调我的。我认为这说明函数重载解析比类特化更难实现(并且由用户使用)。所以可能没有真正的技术障碍(类似于功能模板部分专业化),而是历史性事故。

答案 1 :(得分:19)

您不能“重载”类型参数,非类型参数和模板模板参数,但您可以专门使用可变参数模板:

template <typename... T>
struct Foo;

template <typename T1>
struct Foo<T1> {};

template <typename T1, typename T2>
struct Foo<T1,T2> {};

答案 2 :(得分:1)

这已经存在了一段时间了,但我在搜索时仍然发现了这篇文章。感谢@ log0为我提供了良好的开端。这是一个避免需要为所有可能的枚举提供模板特化的解决方案。它确实做了一个假设:您可以根据自身及其基类定义每个模板扩展。 (这将在下面的Reindex中完成):

FooImpl

template <typename... T> struct Foo; template<typename T> struct Foo<T> { /* implementation of base class goes here*/}; template <typename C, typename Base> struct FooImpl : public Base { /* implementation of derived class goes here */}; template<typename C, typename... Bases> struct Foo<C, Bases...> : FooImpl<C, Foo<Bases...> > { /*NO IMPLEMENTATION HERE */}; 的使用打破了否则会导致模糊的递归。然后允许声明如下:

FooImpl

也许这就是STL现在如何做到的?