在开发一个库时,我发现了一个可以在此片段中总结的代码:
struct MainStream{} default_stream, custom_stream;
struct Stream2{} custom_stream2;
template <class StreamSelection>
class Manage {
public:
Manage(StreamSelection & out_stream = default_stream){
// do something
};
};
void test(void) {
Manage <MainStream> s1_a; //ok: use default_stream
Manage <MainStream> s1_b(default_stream); //ok: use default_stream
Manage <MainStream> s1_c(custom_stream); //ok: use custom_stream
Manage <Stream2> s2_a(custom_stream2); //ok: use custom_stream2
//Manage <Stream2> s2_b; //diagnostic error if uncommented due the incompatible default argument.
}
此类构造函数的目的是在使用
MainStream
实例化模板时提供默认参数,并且在未提供构造函数参数的情况下强制对其他参数产生诊断错误,并且还避免任何额外的模板专门化来实现目的。
也就是说,该代码片段可以按预期使用 GCC (-std=c++11 -pedantic -Wall -Wextra)、CLANG 和 MSVC 进行编译和工作。
不考虑代码风格,问题是:这件事是否涉及未定义的行为?
我能在 ISO 论文 N3337(最终的 C++11 工作草案)第 14.7.1 第 3 点找到的唯一参考:
除非调用是对函数模板显式特化或 显式专用类模板的成员函数, 函数模板或成员函数的默认参数 类模板在调用函数时隐式实例化 在需要默认参数值的上下文中。
但我不确定这个匹配(问题是关于默认参数的类型,而不是它的实例。) 有什么建议吗?
编辑:澄清一下,当使用“MainStream”以外的参数实例化类时,忽略的默认参数无论如何都有不兼容的类型。
[temp.inst/1] 类模板特化的隐式实例化会导致声明的隐式实例化,但不会导致类成员函数的定义或默认参数...
强调我的。再加上您已经找到的段落:
[temp.inst/3] .. 当在需要默认参数值的上下文中调用函数时,函数模板或类模板的成员函数的默认参数将被隐式实例化。
这些规则旨在通过尽可能晚地推迟默认参数的实例化来使代码像您的工作一样,希望不需要它。