Consider the following:
#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;
}
It builds and runs successfully in GCC 4.8, but is it strictly legal?T v = {}
is invalid for T=int&
, but this default argument is not used.
The only pertinent language I can find in the standard does not seem to explicitly explain whether or not this program is valid; none of the following really seems completely relevant, despite touching on the subject in various ways:
[C++11: 8.3.6/1]:
If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument. Default arguments will be used in calls where trailing arguments are missing.
[C++11: 8.3.6/5]:
A default argument is implicitly converted (Clause 4) to the parameter type. The default argument has the same semantic constraints as the initializer in a declaration of a variable of the parameter type, using the copy-initialization semantics (8.5). The names in the default argument are bound, and the semantic constraints are checked, at the point where the default argument appears. Name lookup and checking of semantic constraints for default arguments in function templates and in member functions of class templates are performed as described in 14.7.1. [..]
[C++11: 8.3.6/9]:
Default arguments are evaluated each time the function is called. [..]
See 14.7.1 Implicit instantiation[temp.inst]/13:
If a function template f is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in the default argument is done as if the default argument had been an initializer used in a function template specialization with the same scope, the same template parameters and the same access as that of the function template f used at that point, except that the scope in which a closure type is declared (5.1.2) – and therefore its associated namespaces – remain as determined from the context of the definition for the default argument. This analysis is called default argument instantiation. The instantiated default argument is then used as the argument of f.
The example below it also shows a case where the default argument is ill-formed if instantiated:
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
}
There is no ydef, so the calls that use it are ill-formed, but the calls that don't use it are ok.
C++11, 14.7.1/3:
... Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
(Emphasis mine).
Combine this with 14.7.1/1:
... The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, ...
(Emphasis mine again)
I would say that from the above, it follows that when called so that the default argument value is not required, it is not instantiated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With