Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uniform Initialization with curly brace is mistaken as Initializer List

Tags:

c++

c++11

I have a class as:

#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 is:

#include <iostream>
#include "Object.hpp"

class Foo {};


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

It gives me 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)). It 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 curly brace uniform initialization does not work here? Why is considered an initializater list in this case? Foo does not even have a constructor taking initializer list?

like image 645
SwiftMango Avatar asked Jun 24 '15 20:06

SwiftMango


1 Answers

This was a known issue, and a defect in the standard (see CWG #1467). The proposal has been applied to the latest working paper (§8.5.4 [dcl.init.list]/3):

List-initialization of an object or reference of type T is defined as follows:

  • If T is a class type and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).

Note that trunk versions of Clang and GCC accept this code.

like image 158
David G Avatar answered Nov 19 '22 00:11

David G