50

阅读这个问题让我想知道:是否有不允许类模板重载的技术原因?

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

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++ 中是不可能的?

4

3 回答 3

38

模板完整指南亚马逊)的第 12.5 节包含以下引用:

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

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

相比之下,所有重载的函数模板都必须通过查找被带入一个重载集,它们可能来自不同的命名空间或类。这增加了无意中重载模板名称的可能性。

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

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

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

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

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

大胆强调我的。我将其解释为函数重载解决方案比类专业化更难实现(并且用户正确)。所以可能没有真正的技术障碍(类似于函数模板部分专业化),而是一个历史事故。

于 2012-08-15T12:19:18.597 回答
19

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

template <typename... T>
struct Foo;

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

template <typename T1, typename T2>
struct Foo<T1,T2> {};
于 2012-08-15T12:21:07.840 回答
2

这已经有一段时间了,但我在搜索时仍然找到了这篇文章。感谢@log0 为我提供了一个良好的开端。这是一个避免需要为所有可能的枚举提供模板特化的解决方案。它确实做了一个假设:您可以根据自身及其基类定义每个模板扩展。(这将在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打破了否则会导致的模棱两可的递归。然后,这允许声明如下:

Foo<int> foo_int;
Foo<int, double> foo_int_double;
Foo<int, float, double> foo_int_float_double;

也许这就是 STL 现在的做法?

于 2018-01-13T07:40:13.250 回答