使用大括号的统一初始化被误认为初始化程序列表

Uniform Initialization with curly brace is mistaken as Initializer List

本文关键字:初始化 误认为 程序 列表      更新时间:2023-10-16

我有一个类:

#include <memory>
class Object {
    std::shared_ptr<void> object_ptr;
public:
    Object() {}
    template<typename T>
    Object(T&& object) 
        : object_ptr {new T {std::move(object)} } {}
    virtual ~Object() {};
};

我的主cpp文件是:

#include <iostream>
#include "Object.hpp"
class Foo {};

int main() {
    Object o {Foo{}};
}

它给了我错误:

test/test.cpp:13:20:   required from here
include/Object.hpp:24:49: error: could not convert ‘{std::move<Foo&>((* & object))}’ from ‘<brace-enclosed initializer list>’ to ‘Foo’
         : object_ptr {new T {std::move(object)} } {}
                                                 ^
include/Object.hpp:24:49: error: no matching function for call to ‘std::shared_ptr<void>::shared_ptr(<brace-enclosed initializer list>)’
include/Object.hpp:24:49: note: candidates are:
In file included from /usr/include/c++/4.8/memory:82:0,
                 from include/Object.hpp:7,
                 from test/test.cpp:2:
/usr/include/c++/4.8/bits/shared_ptr.h:314:2: note: template<class _Alloc, class ... _Args> std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...)
  shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:314:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:265:17: note: constexpr std::shared_ptr<_Tp>::shared_ptr(std::nullptr_t) [with _Tp = void; std::nullptr_t = std::nullptr_t]
       constexpr shared_ptr(nullptr_t __p) noexcept
                 ^
/usr/include/c++/4.8/bits/shared_ptr.h:265:17: note:   no known conversion for argument 1 from ‘<type error>’ to ‘std::nullptr_t’
/usr/include/c++/4.8/bits/shared_ptr.h:257:2: note: template<class _Tp1, class _Del> std::shared_ptr<_Tp>::shared_ptr(std::unique_ptr<_Up, _Ep>&&)
  shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:257:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:253:2: note: template<class _Tp1> std::shared_ptr<_Tp>::shared_ptr(std::auto_ptr<_Up>&&)
  shared_ptr(std::auto_ptr<_Tp1>&& __r);
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:253:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:248:11: note: template<class _Tp1> std::shared_ptr<_Tp>::shared_ptr(const std::weak_ptr<_Tp1>&)
  explicit shared_ptr(const weak_ptr<_Tp1>& __r)
           ^
/usr/include/c++/4.8/bits/shared_ptr.h:248:11: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:236:2: note: template<class _Tp1, class> std::shared_ptr<_Tp>::shared_ptr(std::shared_ptr<_Tp1>&&)
  shared_ptr(shared_ptr<_Tp1>&& __r) noexcept
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:236:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:226:7: note: std::shared_ptr<_Tp>::shared_ptr(std::shared_ptr<_Tp>&&) [with _Tp = void]
       shared_ptr(shared_ptr&& __r) noexcept
       ^
/usr/include/c++/4.8/bits/shared_ptr.h:226:7: note:   no known conversion for argument 1 from ‘<type error>’ to ‘std::shared_ptr<void>&&’
/usr/include/c++/4.8/bits/shared_ptr.h:218:2: note: template<class _Tp1, class> std::shared_ptr<_Tp>::shared_ptr(const std::shared_ptr<_Tp1>&)
  shared_ptr(const shared_ptr<_Tp1>& __r) noexcept
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:218:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:206:2: note: template<class _Tp1> std::shared_ptr<_Tp>::shared_ptr(const std::shared_ptr<_Tp1>&, _Tp*)
  shared_ptr(const shared_ptr<_Tp1>& __r, _Tp* __p) noexcept
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:206:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:184:2: note: template<class _Deleter, class _Alloc> std::shared_ptr<_Tp>::shared_ptr(std::nullptr_t, _Deleter, _Alloc)
  shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:184:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:165:2: note: template<class _Tp1, class _Deleter, class _Alloc> std::shared_ptr<_Tp>::shared_ptr(_Tp1*, _Deleter, _Alloc)
  shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:165:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:146:2: note: template<class _Deleter> std::shared_ptr<_Tp>::shared_ptr(std::nullptr_t, _Deleter)
  shared_ptr(nullptr_t __p, _Deleter __d)
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:146:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:129:2: note: template<class _Tp1, class _Deleter> std::shared_ptr<_Tp>::shared_ptr(_Tp1*, _Deleter)
  shared_ptr(_Tp1* __p, _Deleter __d)
  ^
/usr/include/c++/4.8/bits/shared_ptr.h:129:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:112:11: note: template<class _Tp1> std::shared_ptr<_Tp>::shared_ptr(_Tp1*)
  explicit shared_ptr(_Tp1* __p)
           ^
/usr/include/c++/4.8/bits/shared_ptr.h:112:11: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/shared_ptr.h:103:7: note: std::shared_ptr<_Tp>::shared_ptr(const std::shared_ptr<_Tp>&) [with _Tp = void]
       shared_ptr(const shared_ptr&) noexcept = default;
       ^
/usr/include/c++/4.8/bits/shared_ptr.h:103:7: note:   no known conversion for argument 1 from ‘<type error>’ to ‘const std::shared_ptr<void>&’
/usr/include/c++/4.8/bits/shared_ptr.h:100:17: note: constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = void]
       constexpr shared_ptr() noexcept
                 ^
/usr/include/c++/4.8/bits/shared_ptr.h:100:17: note:   candidate expects 0 arguments, 1 provided
make: *** [test.o] Error 1

但是,如果我将new T {std::move(object)}更改为new T (std::move(object))。它起作用:

class Object {
    std::shared_ptr<void> object_ptr;
public:
    Object() {}
    template<typename T>
    Object(T&& object) 
        : object_ptr {new T (std::move(object)) } {}
    virtual ~Object() {};
};

为什么大括号统一初始化在这里不起作用?为什么在这种情况下被认为是一个初始化列表?Foo甚至没有一个构造函数接受初始值设定项列表?

这是一个已知问题,也是标准中的一个缺陷(请参见CWG#1467)。该提案已应用于最新的工作文件(§8.5.4[dcl.init.list]/3):

类型T的对象或引用的列表初始化定义如下:

  • 如果T是类类型,并且初始化器列表具有类型为cv U的单个元素,其中UT或派生的类从T,对象从该元素初始化(通过复制列表初始化的复制初始化,或通过直接列表初始化的直接初始化)

请注意,Clang和GCC的主干版本接受此代码。