我发现如果您使用包装模板使用模板,您可以在首次使用模板后对其进行专门化.简单的例子:
#include <iostream>
template<typename T>
const char* templateImpl();
template<typename T>
const char* templateGetter() { return templateImpl<T>(); }
struct S{};
int main(){ std::cout << templateGetter<S>() << std::endl; return 0; }
template<>
const char* templateImpl<S>(){ return "S"; }
Run Code Online (Sandbox Code Playgroud)
这适用于每个编译器 - 我并不感到惊讶MSVC编译它,因为它处理模板的方式不同,但GCC和clang也允许它.我认为标准要求在第一次使用之前进行专门化,在这种情况下,这意味着在main之前并且期望它们报告错误.
我错过了什么,这个代码符合标准吗?
为了澄清,如果我改变templateGetter<S>对templateImpl<S>主,程序将不会出现错误消息我期望从这一过于编译:
main.cpp:14:29:错误:实例化后'const char*templateImpl()[带T = S]'的特化
T.C*_*.C. 10
你有(不)幸运.这是形成不良的NDR.
6如果模板,成员模板或类模板的成员是明确专门化的,则应在第一次使用该特化之前声明该特化,这将导致发生隐式实例化,在每个使用此类用途的翻译单元中发生 ; 无需诊断.[...]
7为函数模板,类模板,变量模板,类模板的成员函数,类模板的静态数据成员,类模板的成员类,类模板的成员枚举,类模板的成员类模板,成员放置显式特化声明类模板的函数模板,类模板的静态数据成员模板,类模板成员模板的成员函数,非模板类成员模板的成员函数,非模板类的静态数据成员模板,成员类的成员函数模板类模板等的放置,类模板的部分特化声明的放置,变量模板,非模板类的成员类模板,非模板类的静态数据成员模板,类模板的成员类模板等,可以根据显式规范的相对位置来影响程序是否格式正确 ialization声明及其在翻译单元中的实例化点,如上下文所述.写专业时,要注意它的位置; 或者使它编纂将是一种试图点燃其自焚的试验.
p7在这里不是很有用,但我无法抗拒引用它:)
实例化templateGetter<S>导致声明的隐式实例化templateImpl<S>.您没有看到代码出错,因为许多实现都希望在可能的情况下将模板实例化推迟到翻译单元结束,这是一种允许的实现技术.(我不会在这里引用标准,但你会发现函数模板特化在翻译单元的末尾有一个额外的实例化点.)
给出templateGetter推断的返回类型将迫使其早期实例化其身体:
template<typename T>
auto templateGetter() { return templateImpl<T>(); }
Run Code Online (Sandbox Code Playgroud)
和瞧:
+ g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
main.cpp:14:29: error: specialization of 'const char* templateImpl() [with T = S]' after instantiation
const char* templateImpl<S>(){ return "S"; }
^
+ clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
main.cpp:14:13: error: explicit specialization of 'templateImpl<S>' after instantiation
const char* templateImpl<S>(){ return "S"; }
^
main.cpp:7:32: note: implicit instantiation first required here
auto templateGetter() { return templateImpl<T>(); }
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)