c++ - 为什么不能在全特化中引入新的模板参数?

标签 c++ templates c++11 language-lawyer

Where in the C++11 standard does it prohibit 'template <typename T> class A {...}; template <typename T> class A<int> {...};' (if anywhere)? ,已确认 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;
};

在完全理解上述语法不代表有效的 C++ 的情况下,我仍然可以想象上述代码片段在语法上的明确用法,如下所示:

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

a1.t = 2.0f;
a2.i = 2;
a2.t = 2.0;

C++ 支持上述语法在句法和语义上似乎是明确的。

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

我会将此语法描述为“在完全特化中引入新的模板参数”。

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

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

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

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

最佳答案

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

为了清楚起见,我假设你的意思是你的示例代码,

 A<double> a; // okay
 A<int> a2;   // not okay, A<int> is not a class but a class template.

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

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?

还不算太糟;编译器可能会对此提示。不过,我认为我们开始看到这有点奇怪。好吧,把它提高一个档次:

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

Foo<A> f; // this would usually work, does it now?

如果您回答否,如果在编译时不知道特化怎么办?

编辑:稍微扩展一下,考虑一个我喜欢称之为包特征的模板-模板参数的真实场景:

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;

并提供类似 A 的内容,它是除 int 之外的所有内容的类和 int 的类模板。然后努力锻炼

applies_to_all<A, double, float, std::string, int>::value

请注意,这个简单的案例不是您可能看到的代码。你真正得到的是这些东西在其他模板中嵌套了三个层次,看起来像这样:

applies_to_all<A, T...>::value

可能可以为此定义一种在数学上一致的行为,但我怀疑是否可以定义有用的行为。当然,它不符合 POLA。

按照这些思路,您可能会想到更多。以这种方式模糊类和类模板之间的界限势必会破坏各种东西。

关于c++ - 为什么不能在全特化中引入新的模板参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27504121/

相关文章:

C++在删除无效地址时抛出异常

c++ - std::string 到 int8_t

c++ - 类中的函数模板参数推导

c++ - 是否可以为 std::any-like 容器转发具有匹配模板类型的函数调用?

java - 从 Java 导入到 C++ 包括

c++ - Linux - 有时只会出现段错误 - 如何调试

c++ - 如何在 header 和 cpp 之间拆分静态/模板类?

c++ - 为什么在超出容量时 resize() 会导致 vector 内容的复制而不是 move ?

c++ - 无法使用比较器初始化 std::function

c++ - bool 函数作为输入参数