0

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?

iFreilicht
  • 13,271
  • 9
  • 43
  • 74
  • Related: http://stackoverflow.com/q/25850629 and https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-discussion/GJnrg2lUfPg – dyp Sep 21 '14 at 13:24
  • Your "make_unqiue" typo, plus the fact that an exhaustive search of ISO/IEC 14882-2011 finds no mention of a standard library function named "make_unique" indicates that this is not the actual code that you're having problems with, but some random pieces of code that you pulled from the thin air. If you'd like to ask a question and reference some code, please post the actual code that you're having problems with. Thank you. – Sam Varshavchik Sep 21 '14 at 14:45
  • 4
    @SamVarshavchik `make_unique` [is part of C++14](http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) and [already supported in VC](http://msdn.microsoft.com/en-us/library/dn439780.aspx). I have lifted this code directly from a Visual Studio Project and it is the only thing contained in it, apart from an empty main function. The typo must have slipped in during editing. If you see any other ways to improve this question, please tell me. – iFreilicht Sep 21 '14 at 15:02

1 Answers1

5

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.

Community
  • 1
  • 1
  • Ah, I see. The template function `make_unique()` never gets instantiated because MSVC determined that it will never be called, therefore the invalid call to `Foo()` doesn't even exist. Thank you very much. – iFreilicht Sep 21 '14 at 15:14
  • @iFreilicht Re-reading, I think I was completely wrong in this answer. It says "class template definition", referring to not-yet-instantiated parameter and return types in function overloads, *not* referring to the functions themselves. –  Sep 21 '14 at 17:08
  • It sounded like a good explanation. Don't you think the rules you cited apply to function template instantiation as well? – iFreilicht Sep 23 '14 at 10:30
  • @iFreilicht I do think that my explanation covers what VC++ actually does, it's just that contrary to what I originally wrote, I don't think the standard allows it. It's a useful optimisation, and even if currently disallowed, it wouldn't surprise me if in the future, the standard gets changed to permit it. –  Sep 23 '14 at 10:33
  • Ah I get it. Well nobody adheres to the standard 100%, which is a shame, but not at all surprising. I reapproved your answer. – iFreilicht Sep 23 '14 at 10:44