Why can't i initialize a unique pointer
#include <iostream>
#include <memory>
class Widget
{
std::unique_ptr<int[]> arr;
public:
Widget(int size)
{
arr = std::make_unique<int[size]>();
}
~Widget()
{
}
};
int main()
{
}
I am not able to understand the meaning of below error messages. What is wrong with my invocation of
arr = std::make_unique<int[size]>();
I am just trying to create a class with unique pointer member which manages an array. How should I change the below program and WHY?
Error(s):
1129699974/source.cpp: In constructor ‘Widget::Widget(int)’:
1129699974/source.cpp:13:43: error: no matching function for call to ‘make_unique<int [size]>()’
arr = std::make_unique<int[size]>();
^
In file included from /usr/include/c++/7/memory:80:0,
from 1129699974/source.cpp:4:
/usr/include/c++/7/bits/unique_ptr.h:824:5: note: candidate: template<class _Tp, class ... _Args> typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...)
make_unique(_Args&&... __args)
^~~~~~~~~~~
/usr/include/c++/7/bits/unique_ptr.h:824:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/bits/unique_ptr.h: In substitution of ‘template<class _Tp, class ... _Args> typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = int [size]; _Args = {}]’:
1129699974/source.cpp:13:43: required from here
/usr/include/c++/7/bits/unique_ptr.h:824:5: error: ‘int [size]’ is a variably modified type
/usr/include/c++/7/bits/unique_ptr.h:824:5: error: trying to instantiate ‘template<class _Tp> struct std::_MakeUniq’
/usr/include/c++/7/bits/unique_ptr.h:830:5: note: candidate: template<class _Tp> typename std::_MakeUniq<_Tp>::__array std::make_unique(std::size_t)
make_unique(size_t __num)
^~~~~~~~~~~
/usr/include/c++/7/bits/unique_ptr.h:830:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/bits/unique_ptr.h: In substitution of ‘template<class _Tp> typename std::_MakeUniq<_Tp>::__array std::make_unique(std::size_t) [with _Tp = int [size]]’:
1129699974/source.cpp:13:43: required from here
/usr/include/c++/7/bits/unique_ptr.h:830:5: error: ‘int [size]’ is a variably modified type
/usr/include/c++/7/bits/unique_ptr.h:830:5: error: trying to instantiate ‘template<class _Tp> struct std::_MakeUniq’
/usr/include/c++/7/bits/unique_ptr.h:836:5: note: candidate: template<class _Tp, class ... _Args> typename std::_MakeUniq<_Tp>::__invalid_type std::make_unique(_Args&& ...) <deleted>
make_unique(_Args&&...) = delete;
^~~~~~~~~~~
/usr/include/c++/7/bits/unique_ptr.h:836:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/bits/unique_ptr.h: In substitution of ‘template<class _Tp, class ... _Args> typename std::_MakeUniq<_Tp>::__invalid_type std::make_unique(_Args&& ...) [with _Tp = int [size]; _Args = {}]’:
1129699974/source.cpp:13:43: required from here
/usr/include/c++/7/bits/unique_ptr.h:836:5: error: ‘int [size]’ is a variably modified type
/usr/include/c++/7/bits/unique_ptr.h:836:5: error: trying to instantiate ‘template<class _Tp> struct std::_MakeUniq’
You need
arr = std::make_unique<int[]>(size);
make_unique has a specific documented usage:
template< class T > unique_ptr<T> make_unique( std::size_t size );`
... Constructs an array of the given dynamic size. The array elements are value-initialized. This overload participates in overload resolution only if T is an array of unknown bound. The function is equivalent to:
unique_ptr<T>(new std::remove_extent_t<T>[size]())
Conceptually-speaking1, you can think of make_unique as being very similar to std::unique_ptr<T>(new T(...)) where ... represents forwarding of the args passed to make_unique. In this case, the usage is analogous to forwarding the one arg to operator new[] (std::size_t size)
1 The documentation I linked above doesn't say that the arg is forwarded in the array case, and I don't believe the spec does either.
Related
The following code:
#include <array>
template <int i>
auto f(){}
int main () {
std::array{f<5>};
}
compiles with clang 7.0, but fails with gcc 8.2 with the message
prog.cc: In function 'int main()':
prog.cc:7:20: error: class template argument deduction failed:
std::array{f<5>};
^
prog.cc:7:20: error: no matching function for call to 'array(<unresolved overloaded function type>)'
In file included from prog.cc:1:
/opt/wandbox/gcc-8.2.0/include/c++/8.2.0/array:244:5: note: candidate: 'template<class _Tp, class ... _Up> std::array(_Tp, _Up ...)-> std::array<typename std::enable_if<(is_same_v<_Tp, _Up> && ...), _Tp>::type, (1 + sizeof... (_Up))>'
array(_Tp, _Up...)
^~~~~
/opt/wandbox/gcc-8.2.0/include/c++/8.2.0/array:244:5: note: template argument deduction/substitution failed:
prog.cc:7:20: note: couldn't deduce template parameter '_Tp'
std::array{f<5>};
^
In file included from prog.cc:1:
/opt/wandbox/gcc-8.2.0/include/c++/8.2.0/array:94:12: note: candidate: 'template<class _Tp, long unsigned int _Nm> array(std::array<_Tp, _Nm>)-> std::array<_Tp, _Nm>'
struct array
^~~~~
/opt/wandbox/gcc-8.2.0/include/c++/8.2.0/array:94:12: note: template argument deduction/substitution failed:
prog.cc:7:20: note: couldn't deduce template parameter '_Tp'
std::array{f<5>};
^
Is this code legal? If not, how do I fix it?
I believe the program is well formed. I faced a similar problem myself recently. GCC seems to have issues when it needs to deduce the placehoder return type while in the process of deducing the array arguments. Specifying the return type explicitly as void would make GCC accept your code, for instance.
Ultimately, the workaround is to split the declarations.
auto *p = f<5>;
std::array{p};
Following the code in this question, I have a std::bind with a variadic template function. If I try to provide a function template with auto return, gcc rejects the program:
#include <functional>
template <typename... Args
auto inv_impl(Args... a) { return (a + ...); }
template <typename... Args>
auto inv(Args... args) {
auto bound = std::bind(&inv_impl<Args...>, args...);
return bound;
}
int main() {
auto b = inv(1, 2);
}
The compile error is:
foo.cc: In instantiation of ‘auto inv(Args ...) [with Args = {int, int}]’:
foo.cc:41:30: required from here
foo.cc:36:25: error: no matching function for call to ‘bind(<unresolved overloaded function type>, int&, int& ’
auto bound = std::bind(&inv_impl<Args...>, args...);
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from foo.cc:2:
/usr/include/c++/8.1.1/functional:808:5: note: candidate: ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)’
bind(_Func&& __f, _BoundArgs&&... __args)
^~~~
/usr/include/c++/8.1.1/functional:808:5: note: template argument deduction/substitution failed:
foo.cc:36:25: note: couldn't deduce template parameter ‘_Func’
auto bound = std::bind(&inv_impl<Args...>, args...);
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from foo.cc:2:
/usr/include/c++/8.1.1/functional:832:5: note: candidate: ‘template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)’
bind(_Func&& __f, _BoundArgs&&... __args)
^~~~
/usr/include/c++/8.1.1/functional:832:5: note: template argument deduction/substitution failed:
foo.cc:36:25: note: couldn't deduce template parameter ‘_Result’
auto bound = std::bind(&inv_impl<Args...>, args...);
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
foo.cc:37:10: error: unable to deduce ‘auto’ from ‘bound’
return bound;
^~~~~
foo.cc: In function ‘int main()’:
foo.cc:41:8: error: ‘void b’ has incomplete type
auto b = inv<int, int>(1, 2);
^
As far as I see, return types spelled out by me work, and it's only auto return types that the compiler can't handle.
Is there a way I can return from inv_impl without knowing the return type at code-write time?
(I'm playing with declval/decltype constructs but I'm wondering if there's something better)
This is definitely a gcc bug (filed 86826).
The solution is to just... not use std::bind(). There's hardly ever a reason to anyway. Lambdas are strictly superior:
template <typename... Args>
auto inv(Args... args) {
return [=]{ return inv_impl(args...); };
}
The following code compiles well:
int main()
{
variant<any> var;
var = 5;
cout << any_cast<int>(get<any>(var)) << endl;
return 0;
}
But when I'm trying to put variant<any> as a class member
struct MyClass{
variant<any> var;
};
int main()
{
MyClass s;
return 0;
}
It doesn't compile. Am I doing something wrong or it is some bug?
I'm using gcc 7.1.0
In file included from /home/zak/Projects/Anytest/main.cpp:3:0:
/usr/local/gcc-7.1/include/c++/7.1.0/variant: In instantiation of ‘struct std::__detail::__variant::__accepted_index<const std::variant<std::any>&, std::variant<std::any>, void>’:
/usr/local/gcc-7.1/include/c++/7.1.0/variant:911:26: required from ‘constexpr const size_t std::variant<std::any>::__accepted_index<const std::variant<std::any>&>’
/usr/local/gcc-7.1/include/c++/7.1.0/variant:940:6: required by substitution of ‘template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) [with _Tp = const std::variant<std::any>&; <template-parameter-1-2> = <missing>]’
/home/zak/Projects/Anytest/main.cpp:14:13: required from here
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’
decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}]
static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First);
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}]
{ static void _S_fun(); };
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’
decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}]
static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First);
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}]
{ static void _S_fun(); };
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’
decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}]
static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First);
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}]
{ static void _S_fun(); };
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided
/usr/local/gcc-7.1/include/c++/7.1.0/variant: In instantiation of ‘constexpr const size_t std::__detail::__variant::__accepted_index<const std::variant<std::any>&, std::variant<std::any>, void>::value’:
/usr/local/gcc-7.1/include/c++/7.1.0/variant:911:26: required from ‘constexpr const size_t std::variant<std::any>::__accepted_index<const std::variant<std::any>&>’
/usr/local/gcc-7.1/include/c++/7.1.0/variant:940:6: required by substitution of ‘template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) [with _Tp = const std::variant<std::any>&; <template-parameter-1-2> = <missing>]’
/home/zak/Projects/Anytest/main.cpp:14:13: required from here
/usr/local/gcc-7.1/include/c++/7.1.0/variant:564:12: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’
- decltype(__overload_set<_Types...>::
~~~~~~~~~~~~~~~~~~~~~~~~~~~
_S_fun(std::declval<_Tp>()))::value;
~~~~~~^~~~~~~~~~~~~~~~~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}]
static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First);
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}]
{ static void _S_fun(); };
^~~~~~
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided
The problem is with MyClass's implicitly defined copy constructor, when it tries to copy construct the member of type std::variant<std::any>.
To perform overload resolution, the compiler first needs to try to instantiate all of std::variant's constructor templates, with the function argument being a const std::variant<std::any>&1. The constructor of our interest is this one:
template <class T> constexpr variant(T&& t) noexcept(/*...*/);
It only participates in overload resolution if, among others, the expression FUN(std::forward<T>(t)) is well formed, where FUN is a set of overloaded functions produced according to [variant.ctor]/12.2
In this case, there is only one alternative type (std::any), so there is only one imaginary function FUN, whose signature is FUN(std::any). Now, the compiler needs to decide whether FUN can be called with a const std::variant<std::any>&1. In this process, the compiler needs to know whether std::any can be constructed with const std::variant<std::any>&1.
This will trigger the instantiation of std::any's constructor template template<class T> any(T&& value);, which only participates in overload resolution if std::is_copy_constructible_v<VT> is true (VT being std::decay_t<T>, and T being const std::variant<std::any>&).
Now in order to see whether VT (i.e. std::variant<std::any>) is copy constructible, the compiler needs to try to instantiate all of std::variant's constructor templates... and this is where we started, and we are stuck in a loop.
This can explain why we see template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) and __overload_set<std::any>::_S_fun (which corresponds to the function FUN mentioned above) in the error message, and why we see the same error appearing several times.
It remains a question how GCC breaks from the above loop, and why tweaking the program can stop GCC from reporting the error. Maybe these are indication of some bug.
1. Strictly speaking, it should be "an lvalue of type const std::variant<std::any>" rather than "a const std::variant<std::any>&".
2. The standard also requires that this constructor shall only participate in overload resolution if is_same_v<decay_t<T>, variant> is false. GCC (libstdc++) chooses to check that later. I don't know whether this is conforming.
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?
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.
The following code compiles on gcc 4.6 but not 4.7. Is it 4.7's problem or 4.6's problem? Compiled with -std=gnu++0x.
#include <utility>
using namespace std;
struct Z {
};
struct X {
operator Z*() const { return nullptr; }
};
struct Y {
Y(Z*) {}
};
int main() {
pair<int, Y> p(make_pair(0, X()));
}
Error messages:
[hidden]$ g++-mp-4.6 -std=gnu++0x e.cpp
[hidden]$ g++-mp-4.7 -std=gnu++0x e.cpp
e.cpp: In function 'int main()':
e.cpp:17:37: error: no matching function for call to 'std::pair<int, Y>::pair(std::pair<int, X>)'
e.cpp:17:37: note: candidates are:
In file included from /opt/local/include/gcc47/c++/utility:72:0,
from e.cpp:1:
/opt/local/include/gcc47/c++/bits/stl_pair.h:204:9: note: template<class ... _Args1, long unsigned int ..._Indexes1, class ... _Args2, long unsigned int ..._Indexes2> std::pair::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>)
/opt/local/include/gcc47/c++/bits/stl_pair.h:204:9: note: template argument deduction/substitution failed:
e.cpp:17:37: note: 'std::pair<int, X>' is not derived from 'std::tuple<_Args1 ...>'
In file included from /opt/local/include/gcc47/c++/utility:72:0,
from e.cpp:1:
/opt/local/include/gcc47/c++/bits/stl_pair.h:153:9: note: template<class ... _Args1, class ... _Args2> std::pair::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>)
/opt/local/include/gcc47/c++/bits/stl_pair.h:153:9: note: template argument deduction/substitution failed:
e.cpp:17:37: note: cannot convert 'std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = X; typename std::__decay_and_strip<_T2>::__type = X; typename std::__decay_and_strip<_T1>::__type = int]((* & X()))' (type 'std::pair<int, X>') to type 'std::piecewise_construct_t'
In file included from /opt/local/include/gcc47/c++/utility:72:0,
from e.cpp:1:
/opt/local/include/gcc47/c++/bits/stl_pair.h:148:12: note: template<class _U1, class _U2, class> constexpr std::pair::pair(std::pair<_U1, _U2>&&)
/opt/local/include/gcc47/c++/bits/stl_pair.h:148:12: note: template argument deduction/substitution failed:
/opt/local/include/gcc47/c++/bits/stl_pair.h:145:38: error: no type named 'type' in 'struct std::enable_if<false, void>'
/opt/local/include/gcc47/c++/bits/stl_pair.h:142:12: note: template<class _U1, class _U2, class> constexpr std::pair::pair(_U1&&, _U2&&)
/opt/local/include/gcc47/c++/bits/stl_pair.h:142:12: note: template argument deduction/substitution failed:
e.cpp:17:37: note: candidate expects 2 arguments, 1 provided
In file included from /opt/local/include/gcc47/c++/utility:72:0,
from e.cpp:1:
/opt/local/include/gcc47/c++/bits/stl_pair.h:136:12: note: template<class _U2, class> constexpr std::pair::pair(const _T1&, _U2&&)
/opt/local/include/gcc47/c++/bits/stl_pair.h:136:12: note: template argument deduction/substitution failed:
e.cpp:17:37: note: cannot convert 'std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = X; typename std::__decay_and_strip<_T2>::__type = X; typename std::__decay_and_strip<_T1>::__type = int]((* & X()))' (type 'std::pair<int, X>') to type 'const int&'
In file included from /opt/local/include/gcc47/c++/utility:72:0,
from e.cpp:1:
/opt/local/include/gcc47/c++/bits/stl_pair.h:131:12: note: template<class _U1, class> constexpr std::pair::pair(_U1&&, const _T2&)
/opt/local/include/gcc47/c++/bits/stl_pair.h:131:12: note: template argument deduction/substitution failed:
e.cpp:17:37: note: candidate expects 2 arguments, 1 provided
In file included from /opt/local/include/gcc47/c++/utility:72:0,
from e.cpp:1:
/opt/local/include/gcc47/c++/bits/stl_pair.h:122:7: note: std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = int; _T2 = Y; std::pair<_T1, _T2> = std::pair<int, Y>]
/opt/local/include/gcc47/c++/bits/stl_pair.h:122:7: note: no known conversion for argument 1 from 'std::pair<int, X>' to 'std::pair<int, Y>&&'
/opt/local/include/gcc47/c++/bits/stl_pair.h:119:17: note: constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = int; _T2 = Y; std::pair<_T1, _T2> = std::pair<int, Y>]
/opt/local/include/gcc47/c++/bits/stl_pair.h:119:17: note: no known conversion for argument 1 from 'std::pair<int, X>' to 'const std::pair<int, Y>&'
/opt/local/include/gcc47/c++/bits/stl_pair.h:116:12: note: template<class _U1, class _U2, class> constexpr std::pair::pair(const std::pair<_U1, _U2>&)
/opt/local/include/gcc47/c++/bits/stl_pair.h:116:12: note: template argument deduction/substitution failed:
/opt/local/include/gcc47/c++/bits/stl_pair.h:113:38: error: no type named 'type' in 'struct std::enable_if<false, void>'
/opt/local/include/gcc47/c++/bits/stl_pair.h:104:26: note: constexpr std::pair<_T1, _T2>::pair(const _T1&, const _T2&) [with _T1 = int; _T2 = Y]
/opt/local/include/gcc47/c++/bits/stl_pair.h:104:26: note: candidate expects 2 arguments, 1 provided
/opt/local/include/gcc47/c++/bits/stl_pair.h:100:26: note: constexpr std::pair<_T1, _T2>::pair() [with _T1 = int; _T2 = Y]
/opt/local/include/gcc47/c++/bits/stl_pair.h:100:26: note: candidate expects 0 arguments, 1 provided
That shouldn't compile.
The initialisation of p.second requires an implicit conversion from X to Y. An implicit conversion can only involve at most one user-defined conversion The required conversion would require two; X to Z* via the conversion operator, and Z* to Y via the conversion constructor.
Initialisation of pair elements from another pair is only allowed via implicit conversions. C++11 says:
20.3.2/12 This constructor shall not participate in overload resolution unless const U& is implicitly convertible to first_type and const V& is implicitly convertible to second_type.
and C++98 said:
20.2.2/4 Initializes members from the corresponding members of the argument, performing implicit conversions as needed.
Presumably, the older version had a bug which allowed this conversion to be considered, and that bug has been fixed in the more recent version.