Unified initialization with a brace is erroneous as a list of initializers

I have a class like:

#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() {}; }; 

My main cpp file:

 #include <iostream> #include "Object.hpp" class Foo {}; int main() { Object o {Foo{}}; } 

This gives me an error:

 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 

However, if I change new T {std::move(object)} to new T (std::move(object)) . He works:

 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() {}; }; 

Why does brace with uniform initialization not work here? Why in this case is considered an initializer list? Foo doesn't even have a constructor that accepts a list of initializers?

+5
source share
1 answer

This was a known issue and defect in the standard (see CWG # 1467 ). The proposal was applied to the last working document (ยง8.5.4 [dcl.init.list] / 3):

An initialization list of an object or link of type T is defined as follows:

  • If T is a class type, and in the initialization list there is one element of type cv U , where U is T or the received class from T , the object is initialized from this element (by copy initialization to initialize the copy list or by direct initialization to initialize the direct list).

Note that trunk Clang and GCC versions accept this code.

+4
source

All Articles