为什么不能在完全专业化中引入新模板参数?

Dan*_*aum 3 c++ templates language-lawyer c++11

C++ 11标准中的位置它禁止'template <typename T> class A {...}; template <typename T> class A <int> {...};' (如果有的话)?,已经确认在C++ 11标准中不允许使用以下语法:

/* invalid C++ */

template <typename T>
class A
{
    public:
    T t;
};

// phony "full specialization" that mistakenly attempts
// to introduce a *new* template parameter
template <typename T>
class A<int>
{
    public:
    int i;
    T t;
};
Run Code Online (Sandbox Code Playgroud)

完全理解上面的语法并不代表有效的C++,但我可以想象一下语法上明确使用上面的代码片段,如下所示:

A<float> a1;
A<int><double> a2;

a1.t = 2.0f;
a2.i = 2;
a2.t = 2.0;
Run Code Online (Sandbox Code Playgroud)

对于C++来说,支持上面的语法似乎在语法上和语义上都是明确的.

(如果任何人都不清楚预期的语义,请发表评论,我会解释.)

我会将此语法描述为"在完全专业化中引入新模板参数".

在这个被修改为支持上述语法和语义的C++编译器的想象场景中,编译器将看到A<int> a2;并识别出尝试的实例化与主模板匹配; 然后它将搜索特化并找到并选择完整的专业化A<int>(忽略<double>); 然后会注意到这个完整的特化引入了一个新的模板参数T,在声明的变量的情况下a2是一个double.

如果我说上面的语法和语义是明确的,那么我想知道为什么这不是C++的一部分.我可以想到三个原因,但也许答案是不同的或更复杂的.

  • (几乎)没有现实世界的场景,这将是有用的
  • 对于要求支持当前编译器而言,这太复杂了
  • 与其他语言功能存在太多潜在冲突,需要许多新规则
  • 实际上,第四种可能性 - 上述语法和语义在某些现实场景中会很有用,并且可以合理地包含在标准中,但它不是当前标准的一部分.

我想知道为什么C++不支持这个 - 我是否正确我的一个要点提供了答案?

Win*_*ute 5

哦,这会以有趣的方式爆炸.

为清楚起见,我假设您的意思是使用您的示例代码,

 A<double> a; // okay
 A<int> a2;   // not okay, A<int> is not a class but a class template.
Run Code Online (Sandbox Code Playgroud)

现在让我们尝试在其他模板中使用它.考虑

template<typename T>
void function<A<T> const &a) { ... }

A<double> a;
A<int><double> a2;

function(a);  // that looks okay.
function(a2); // er...compiler error, I guess?
Run Code Online (Sandbox Code Playgroud)

那还不错; 编译器可能会抱怨这一点.我想我们已经开始看到这有点奇怪了.好吧,把它提升一个档次:

template<template<typename> class A> struct Foo { ... };

Foo<A> f; // this would usually work, does it now?
Run Code Online (Sandbox Code Playgroud)

如果你回答否,如果在编译时不知道专业化怎么办?

编辑:扩展这一点,考虑模板模板参数的真实场景,我喜欢调用包特征:

template<template<typename> class, typename...> struct applies_to_all;

template<template<typename> class predicate, typename T, typename... Pack>
struct applies_to_all<predicate, T, Pack...> {
  static bool const value =
    predicate<T>::value && applies_to_all<predicate, Pack...>::value;
};

template<template<typename> class predicate>
struct applies_to_all<predicate> {
  static bool const value = true;
};

...

bool b = applies_to_all<std::is_integral, int, long, double>::value;
Run Code Online (Sandbox Code Playgroud)

并提供这样的东西A,这是一个类,除了int和一个类模板int.然后尝试解决

applies_to_all<A, double, float, std::string, int>::value
Run Code Online (Sandbox Code Playgroud)

请注意,这个简单的情况并不是您可能会看到的代码.你真正得到的是这些东西嵌套在其他模板的三个层次深处,它看起来像这样:

applies_to_all<A, T...>::value
Run Code Online (Sandbox Code Playgroud)

可能会为此定义一个在数学上一致的行为,但我怀疑可以定义一个有用的行为.当然它不符合POLA标准.

你可以在这些方面提出更多的建议.以这种方式模糊类和类模板之间的界限必将打破各种各样的东西.