c++ 为什么不能重载类模板?

emeijp43  于 2023-05-02  发布在  其他
关注(0)|答案(3)|浏览(134)

阅读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++中是不可能的。

w8f9ii69

w8f9ii691#

    • 模板完整指南**(Amazon)中的第12.5节包含以下引文:

您可能会想知道为什么只有类模板可以部分专用化。原因主要是历史性的。也许可以为函数模板定义相同的机制(参见第13章)。
在某些方面,重载函数模板的效果是相似的,但也有一些细微的差异。这些差异主要与以下事实有关:当遇到使用时,需要查找主模板。专门化只是在之后才考虑,以确定应该使用哪种实现。
相反,所有重载的函数模板都必须通过查找它们而被带入重载集,它们可能来自不同的命名空间或类。这在一定程度上增加了无意中重载模板名称的可能性。
相反,也可以想象允许类模板的重载形式。下面是一个例子:

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

然而,似乎并不迫切需要这样的机制。
此外,the Design and Evolution of C++Amazon)在第15节中包含了这句话。10.3
因此,我得出结论,我们需要一种“专门化”模板的机制。这可以通过接受一般的重载或通过一些更具体的机制来实现。我选择了一个特定的机制,因为我认为我主要是解决由C中的违规行为引起的违规行为,并且因为超载的建议总是会引起抗议。我试图保持谨慎和保守;我现在认为这是一个错误最初定义的专业化是一种受限制的、反常的重载形式,与语言的其他部分格格不入。
大胆强调我的。我将此解释为函数重载解析比类专门化更难实现(并被用户正确理解)。所以可能没有真实的的技术障碍(类似于函数模板部分专门化),而是一个历史事故。

7uzetpgm

7uzetpgm2#

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

template <typename... T>
struct Foo;

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

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

sbdsn5lh3#

这已经有一段时间了,但我在搜索时仍然发现了这篇文章。感谢@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现在所做的?

相关问题