W.F*_*.F. 12 c++ template-templates language-lawyer template-argument-deduction c++17
昨天我问了一个关于模板模板参数的扣除指南使用保证的问题.当Barry改变了对代码标准符合性确认的答案时,我感到非常惊讶.令我惊讶的是,实际上并不是因为扣除指南可以应用于模板模板参数,而是来自符合此合规性的标准部分,即[temp.param]/3:
标识符不遵循省略号的类型参数将其标识符定义为模板声明范围内的typedef-name(如果未声明
template)或template-name(如果声明template).
加上[temp.deduct.guide]/1和simple-template-id规则可以创建一个接受任何模板的通用推理指南.
#include <string>
template <class T>
struct Foo {
Foo(T) { }
};
template <template <class> class TT>
TT(const char *) -> TT<std::string>;
int main() {
Foo foo("abc");
}
Run Code Online (Sandbox Code Playgroud)
代码导致gcc因内部错误而崩溃,并导致clang中的编译错误.说实话,我并不是说代码应该在C++中实际允许,但认为当前的措辞确实使它符合要求.我错过了一些不允许代码的重要规则吗?
冒着犯错的风险,我会引用一个现已删除的答案
如果我没记错的话,这与 [temp.deduct.guide]p3 相冲突:
simple-template-id 应命名类模板专业化。
TT<std::string>没有命名类模板专业化,并且您的代码格式不正确。[temp.spec]p4 中也有这个:
特化是实例化或显式特化的类、函数或类成员。
TT从技术上讲,它是一个模板类型参数。该构造TT<std::string>是一个依赖于类型的type-name。如果推导指南是一个实际的函数模板并且我们将其实例化,TT<std::string>则可以将其实例化为引用类模板专门化的类名。它还可以引用intifTT被实例化以引用适当定义的别名模板。但按原样,在推导指南声明中,它尚未命名类模板专业化。
[temp.res]p8.5.5 有一条规则说
否则,对于可以生成有效专业化的模板,不应发出任何诊断信息。
那么,演绎指南的专业化到底能发生吗?我不同意。首先,它不是一个可以实例化的“模板实体”(参见[temp]p8)。类模板参数推导的特长是基于推导指南形成的一组模板,而不是指南本身。参见[over.match.class.deduct]p1.4
[...]对于每个推导指南,[形成]具有以下属性的函数或函数模板:[...]
这些函数模板在重载解析过程中进一步专业化。推导指南本身从来都不是特化的,因此,我们可以生成一条诊断消息,以检查是否违反了推导指南中的simple-template-id未命名类模板特化的规则。
理查德举了一个不同的例子
template<typename T> class X { T t; };
template<typename T> using Y = X<T*>;
template<typename T> Y(T) -> Y<T>;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,它更复杂,我认为这可能是措辞所允许的,因为Y<T>实际上是类模板专业化。在应用重写规则后,您现在可以争论它是否真正命名了专业化,或者仅仅表示它。IMO 认为,它可以允许争论的事实似乎足以保证缺陷报告。