tmlen tmlen - 1 year ago 51
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;

This compiles fine on Clang and GCC.
gets instantiated even though the return type of
can not be deduced (there is no
). It fails only when
gets called.

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

Answer Source

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 ([]/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

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.