Lig*_*ica 7 c++ language-lawyer c++11
考虑以下:
#include <iostream>
template <typename T>
struct Foo
{
Foo (T v = {}) : var (v) {}
T var;
};
int main()
{
// Foo<int&> f; // cannot compile
int x = 42;
Foo<int&> f(x);
std::cout << f.var;
}
Run Code Online (Sandbox Code Playgroud)
它在GCC 4.8中成功构建并运行,但它是否严格合法?
T v = {}无效T=int&,但不使用此默认参数.
我在标准中找到的唯一相关语言似乎没有明确解释该程序是否有效; 尽管以各种方式触及了这个主题,但以下所有内容都没有真正相关:
[C++11: 8.3.6/1]:如果在参数声明中指定了initializer子句,则此initializer子句将用作默认参数.默认参数将用于缺少尾随参数的调用中.
[C++11: 8.3.6/5]:默认参数被隐式转换(第4节)到参数类型.使用复制初始化语义(8.5),默认参数与参数类型变量声明中的初始化程序具有相同的语义约束.默认参数中的名称是绑定的,并且在出现默认参数的位置检查语义约束.如14.7.1中所述,执行函数模板和类模板的成员函数中的默认参数的语义约束的名称查找和检查.[..]
[C++11: 8.3.6/9]:每次调用函数时都会计算默认参数. [..]
Vil*_*nen 12
请参见14.7.1隐式实例化[temp.inst]/13:
如果以需要使用默认参数的方式调用函数模板f,则查找从属名称,检查语义约束,并且默认参数中使用的任何模板的实例化都像默认参数一样完成已经在5.1.2函数模板专业化使用具有相同的范围,同样的模板参数和相同的访问作为在该点使用的,不同的是在其中一个闭合类型声明的范围的功能模板的F的初始化( ) - 因此其关联的命名空间 - 保持从默认参数的定义的上下文中确定.此分析称为默认参数实例化.然后将实例化的默认参数用作f的参数.
下面的示例还显示了如果实例化默认参数格式错误的情况:
template<class T> void f(T x, T y = ydef(T()), T z = zdef(T()));
class
A { };
A zdef(A);
void g(A a, A b, A c) {
f(a, b, c); // no default argument instantiation
f(a, b); // default argument z = zdef(T()) instantiated
f(a); // ill-formed; ydef is not declared
}
Run Code Online (Sandbox Code Playgroud)
没有ydef,因此使用它的调用是格式错误的,但是不使用它的调用是可以的.
C++ 11,14.7.1/3:
...除非调用函数模板显式特化或显式专用类模板的成员函数,否则在调用函数时隐式实例化函数模板的默认参数或类模板的成员函数.需要默认参数值的上下文 .
(强调我的).
结合14.7.1/1:
... 类模板特化的隐式实例化导致类成员函数的声明的隐式实例化,而不是定义或默认参数的隐式实例化,...
(再次强调我的意见)
我会说,从上面可以看出,当被调用以便不需要默认参数值时,它不会被实例化.