iFreilicht
iFreilicht

Reputation: 14484

Why does std::make_unique not require an argument in a default member initialisation if it is never called?

A default member initialisation needs to reference an existing constructor, no matter if it is ever used or not. So, looking at a struct Foo which has no default constructor:

struct Foo{
    Foo(int x) : x_(x){}
    int x_;
};

It is clear that the following wouldn't work, and leads to a compilation error:

class Bar0{
    Foo foo = Foo(); #constructor Foo() doesn't exist
    Bar0() : foo(0){}
}

But, it is a different story with std::unique_ptr and std::make_unique:

class Bar1{
    unique_ptr<Foo> foo = make_unique<Foo>(); #compiler doesn't complain
    Bar1() : foo(make_unique<Foo>(0)){}
}

This is puzzling, as the compilation fails as soon as Bar1 contains one constructor where foo is not in the initialiser list.

I can confirm this to be true of MSVC12. Could it be a compiler bug?

Upvotes: 1

Views: 3759

Answers (1)

user743382
user743382

Reputation:

Here is a self-contained sample demonstrating the problem:

template <typename T>
int f() {
  return T();
}

struct S {
  int i = f<void>();
  S() : i(0) { }
};

In your example, f is named make_unique, and it doesn't return int, but that doesn't fundamentally change anything.

Yes, Visual Studio's compiler accepts that, and other compilers don't. Visual Studio delays instantiating the templates it doesn't yet need. Other compilers instantiate f<void> as soon as they spot the reference.

Quoting from C++11:

14.7.1 Implicit instantiation [temp.inst]

9 If a function template or a member function template specialization is used in a way that involves overload resolution, a declaration of the specialization is implicitly instantiated (14.8.3).

This supports the compilers that issue an error: f<void>() requires overload resolution, so this instantiates f<void>. There's some leeway for class template instantiations:

14.7.1 Implicit instantiation [temp.inst]

6 If the overload resolution process can determine the correct function to call without instantiating a class template definition, it is unspecified whether that instantiation actually takes place.

but (contrary to what I initially wrote in my answer) I don't think it applies to whole function bodies.

Unless there is a similar exception for function templates, and I haven't been able to find one, I think compilers are required to diagnose the error, and lazy instantiation is not actually currently allowed for function templates.

Upvotes: 5

Related Questions