如果 std::make_unique 从未被调用,为什么在默认成员初始化中不需要参数?

iFr*_*cht 0 c++ default initialization unique-ptr c++11

默认成员初始化需要引用现有的构造函数,无论它是否被使用过。因此,查看一个Foo没有默认构造函数的结构:

struct Foo{
    Foo(int x) : x_(x){}
    int x_;
};
Run Code Online (Sandbox Code Playgroud)

很明显,以下内容不起作用,并导致编译错误:

class Bar0{
    Foo foo = Foo(); #constructor Foo() doesn't exist
    Bar0() : foo(0){}
}
Run Code Online (Sandbox Code Playgroud)

但是,它是一个不同的故事std::unique_ptrstd::make_unique

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

这是令人费解的,因为只要Bar1包含一个foo不在初始化列表中的构造函数,编译就会失败。

我可以确认这对 MSVC12 来说是正确的。可能是编译器错误吗?

小智 5

这是一个自包含的示例,演示了该问题:

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

struct S {
  int i = f<void>();
  S() : i(0) { }
};
Run Code Online (Sandbox Code Playgroud)

在您的示例中,f被命名为make_unique,并且它不会返回int,但这不会从根本上改变任何东西。

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.