Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a program, that doesn't use a default argument that would fail to bind to a reference parameter, legal?

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. [..]

like image 928
Lightness Races in Orbit Avatar asked Oct 17 '14 09:10

Lightness Races in Orbit


2 Answers

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.

like image 60
Ville Voutilainen Avatar answered Sep 28 '22 00:09

Ville Voutilainen


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.

like image 29
Angew is no longer proud of SO Avatar answered Sep 28 '22 01:09

Angew is no longer proud of SO