tmlen tmlen - 3 months ago 7
C++ Question

Template instantiation with undefined member function return types

struct Value {
using a_type = int;
a_type f() { return 1; }
};

template<typename T>
struct Wrapper {
T t;
auto call_f() { return t.f(); }
};

int main() {
Wrapper<Value> w;
Wrapper<int> w2;
w.call_f();
}


This compiles fine on Clang and GCC.
Wrapper<int>
gets instantiated even though the return type of
Wrapper<int>::call_f()
can not be deduced (there is no
int::f()
). It fails only when
w2.call_f()
gets called.

Is this part of the C++ standard, and can it be expected to work on all compilers?

Answer

Yes, this is part of the C++ standard.

The rules of template instantiation are long and complex, but the short version is that a member function of a template class is only instantiated when needed. If nothing calls it, or tries to take a pointer to it, or explicitly instantiates it (and probably a few other cases that I'm forgetting), then it won't be instantiated and your code is well-formed.

As @dyp points out, it is only the declaration of the member function which is instantiated when the class definition is instantiated ([temp.inst]/1), but the return type deduction is only carried out when the function definition is instantiated ([dcl.spec.auto]/12).

This is extremely helpful both for minimising the overhead of templates and being permissive about type requirements. It's this feature which lets you do something like this:

struct Foo {
    //no default constructor
    Foo(int);
};

std::vector<Foo> foos;

Some std::vector functions (resize, for example) require T to be default-constructible, but as long as you don't call those functions you can still use other features of std::vector.

Comments