Constructor Confusion

I have this return as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* Clarification
   - ExtensionType is a strongly typed enum
   - Build returns a pointer of type RobotExtension*
*/
return new Robot({
   Build(ExtensionType::Frame),
   Build(ExtensionType::Chassis),
   Build(ExtensionType::BRAIN),
   Build(ExtensionType::SensorModule),
   Build(ExtensionType::DrillArm),
   Build(ExtensionType::GrabbingArm),
   Build(ExtensionType::GrabbingArm),
   Build(ExtensionType::DriverWheel),
   Build(ExtensionType::DriverWheel),
   Build(ExtensionType::DriverWheel),
   Build(ExtensionType::DriverWheel),
   Build()
});

That should be using this constructor:
 
Robot(const list<unique_ptr<RobotExtensions>>& ={});


But the compiler is unable to convert the arguments.
I tried switching out the Build function with new operators:
1
2
3
4
return new Robot({
   new Frame(), //RobotExtension derivation
 //...
});

But the same errors occur.

I'm new to using smart pointers, so I am probably missing something important. What am I missing?
What is the exact compiler error? Copy and paste.
Truncated to make it a little easier to read.

C:\...\BotTemplate.cpp||In function 'Robot* Assemble(RobotTemplate)':|
C:\...\BotTemplate.cpp|22|error: no matching function for call to 'Robot::Robot(<brace-enclosed initializer list>)'|
C:\...\BotTemplate.cpp|22|note: candidates are:|
C:\...\BotTemplate.h|23|note: Robot::Robot(const std::list<std::unique_ptr<RobotExtensions> >&)|
C:\...\BotTemplate.h|23|note:   no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'const std::list<std::unique_ptr<RobotExtensions> >&'|
C:\...\BotTemplate.h|22|note: Robot::Robot()|
C:\...\BotTemplate.h|22|note:   candidate expects 0 arguments, 1 provided|
C:\...\BotTemplate.h|21|note: Robot::Robot(const Robot&)|
C:\...\BotTemplate.h|21|note:   no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'const Robot&'|
C:\...\BotTemplate.h|21|note: Robot::Robot(Robot&&)|
C:\...\BotTemplate.h|21|note:   no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'Robot&&'|
Daleth wrote:
C:\...\BotTemplate.cpp|22|error: no matching function for call to 'Robot::Robot(<brace-enclosed initializer list>)'|
It thinks you are trying to call the constructor that takes a std::initializer_list. Try specifying that you want to use std::list's constructor that takes a std::initializer_list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
return new Robot(std::list<std::unique_ptr<RobotExtensions>>{
   Build(ExtensionType::Frame),
   Build(ExtensionType::Chassis),
   Build(ExtensionType::BRAIN),
   Build(ExtensionType::SensorModule),
   Build(ExtensionType::DrillArm),
   Build(ExtensionType::GrabbingArm),
   Build(ExtensionType::GrabbingArm),
   Build(ExtensionType::DriverWheel),
   Build(ExtensionType::DriverWheel),
   Build(ExtensionType::DriverWheel),
   Build(ExtensionType::DriverWheel),
   Build()
});
This is one of many reasons that templated types are often aliased:
1
2
3
4
5
6
7
8
9
10
11
using Extensions_t = std::list<std::unique_ptr<RobotExtensions>>;

//...

Robot(Extensions_t const & = {});

//...

return new Robot(Extensions_t{

//... 
For me, this saves a lot of typing :)
Last edited on
Oh, thanks! I thought that the compiler would initialize a std::initializer_list and use that to initialize a std::list object.

Edit:
Nevermind... It didn't work. New error...

I am very confuzzled.

C:\...\BotTemplate.cpp||In function 'Robot* Assemble(RobotTemplate)':|
C:\...\BotTemplate.cpp|22|error: no matching function for call to 'std::list<std::unique_ptr<RobotExtensions> >::list(<brace-enclosed initializer list>)'|
C:\...\BotTemplate.cpp|22|note: candidates are:|
c:\codeblocks_v12\mingw\bin\..\lib\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|642|note: template<class _InputIterator> std::list::list(_InputIterator, _InputIterator, const allocator_type&)|
c:\codeblocks_v12\mingw\bin\..\lib\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|642|note:   template argument deduction/substitution failed:|
C:\...\BotTemplate.cpp|22|note:   cannot convert 'Build((ExtensionType)7, (* & * & std::list<std::unique_ptr<RobotPart> >()))' (type 'RobotExtensions*') to type 'const allocator_type& {aka const std::allocator<std::unique_ptr<RobotExtensions> >&}'|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|625|note: std::list<_Tp, _Alloc>::list(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = std::unique_ptr<RobotExtensions>; _Alloc = std::allocator<std::unique_ptr<RobotExtensions> >; std::list<_Tp, _Alloc>::allocator_type = std::allocator<std::unique_ptr<RobotExtensions> >]|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|625|note:   candidate expects 2 arguments, 12 provided|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|614|note: std::list<_Tp, _Alloc>::list(std::list<_Tp, _Alloc>&&) [with _Tp = std::unique_ptr<RobotExtensions>; _Alloc = std::allocator<std::unique_ptr<RobotExtensions> >; std::list<_Tp, _Alloc> = std::list<std::unique_ptr<RobotExtensions> >]|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|614|note:   candidate expects 1 argument, 12 provided|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|602|note: std::list<_Tp, _Alloc>::list(const std::list<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<RobotExtensions>; _Alloc = std::allocator<std::unique_ptr<RobotExtensions> >; std::list<_Tp, _Alloc> = std::list<std::unique_ptr<RobotExtensions> >]|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|602|note:   candidate expects 1 argument, 12 provided|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|575|note: std::list<_Tp, _Alloc>::list(std::list<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = std::unique_ptr<RobotExtensions>; _Alloc = std::allocator<std::unique_ptr<RobotExtensions> >; std::list<_Tp, _Alloc>::size_type = unsigned int; std::list<_Tp, _Alloc>::value_type = std::unique_ptr<RobotExtensions>; std::list<_Tp, _Alloc>::allocator_type = std::allocator<std::unique_ptr<RobotExtensions> >]|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|575|note:   candidate expects 3 arguments, 12 provided|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|563|note: std::list<_Tp, _Alloc>::list(std::list<_Tp, _Alloc>::size_type) [with _Tp = std::unique_ptr<RobotExtensions>; _Alloc = std::allocator<std::unique_ptr<RobotExtensions> >; std::list<_Tp, _Alloc>::size_type = unsigned int]|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|563|note:   candidate expects 1 argument, 12 provided|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|551|note: std::list<_Tp, _Alloc>::list(const allocator_type&) [with _Tp = std::unique_ptr<RobotExtensions>; _Alloc = std::allocator<std::unique_ptr<RobotExtensions> >; std::list<_Tp, _Alloc>::allocator_type = std::allocator<std::unique_ptr<RobotExtensions> >]|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|551|note:   candidate expects 1 argument, 12 provided|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|543|note: std::list<_Tp, _Alloc>::list() [with _Tp = std::unique_ptr<RobotExtensions>; _Alloc = std::allocator<std::unique_ptr<RobotExtensions> >]|
c:\...\gcc\mingw32\4.7.1\include\c++\bits\stl_list.h|543|note:   candidate expects 0 arguments, 12 provided|
Last edited on
I think it was decided that you have to show proper intent to get what you want, because there can be unintended effects with implicit conversions like that. If anything, newer C++ standards are trying to avoid implicit conversions.
I'll keep that in mind, thanks.

Updated code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//...
using std::list;
using std::unique_ptr;
//...
using  Extension_t = list<unique_ptr<RobotExtensions>>;

Robot* Assemble(RobotTemplate choice){
   switch(choice){
      case RobotTemplate::Basic:
         return new Robot(Extension_t{
            Build(ExtensionType::Frame),
            Build(ExtensionType::Chassis),
            Build(ExtensionType::BRAIN),
            Build(ExtensionType::SensorModule),
            Build(ExtensionType::DrillArm),
            Build(ExtensionType::GrabbingArm),
            Build(ExtensionType::GrabbingArm),
            Build(ExtensionType::DriverWheel),
            Build(ExtensionType::DriverWheel),
            Build(ExtensionType::DriverWheel),
            Build(ExtensionType::DriverWheel),
            Build()
         });
//...
   }
}


I have tried typing out list<unique_ptr<RobotExtensions>> but that didn't work either.
Last edited on
Does Build() have the same return type as Build(ExtensionType::Something)? std::inializer_list requires all elements in the initializer list to be of the same type.
Last edited on
I edited my premature celebration post to include the new compiler error. I must have jinxed myself.
Sorry, deleted and re-wrote my post. Also, you should use Extensions_t, not Extension_t - in many styles, Extension_t would be understood to be one thing, not a collection of things.
Last edited on
Build(ExtensionType) has a default parameter. Build() is the same as Build(ExtensionType::None).
And okay. I haven't been fortunate enough to learn from a tutorial that taught naming conventions and coding styles, but that will soon change.
I'm trying to figure this out, it's more complex than I originally thought:

http://ideone.com/OWnr2P

For one thing, you shouldn't be using std::list like this - std::vector is much more suitable on several orders of magnitude.

Try changing from std::list to std::vector (this still doesn't fix the errors though, but it's better)
Last edited on
Ah, it seems this is not currently possible, not in C++11:
http://stackoverflow.com/questions/8468774/can-i-list-initialize-a-vector-of-move-only-type
Try the second answer instead.

Maybe C++14 will address this.
Last edited on
@L B,
afaik, you can't do that with a std::unique_ptr because it calls the copy constructor which has been implicitly deleted.
Use std::shared_ptr instead?

EDIT:
Oh you figured it out already.
Last edited on
Just my luck. Of course I take the route to nowheresville.

I'll try refactoring my code to use the answer you linked to.
@Thumper: std::shared_ptr is costly, and with a workaround std::unique_ptr can still be used as efficiently as intended ;)
Miracle time!

As I tried modifying the algorithm from what L B referenced to work with my code, I found that I had to explicitly call the std::unique_ptr constructor. So I tried using that with my original code, and it worked! Guess I wasn't doing something completely impossible. =D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//New code:
using RE_uptr = unique_ptr<RobotExtensions>;
//...
return new Robot({
      RE_uptr(Build(ExtensionType::Frame)),
      RE_uptr(Build(ExtensionType::Chassis)),
      RE_uptr(Build(ExtensionType::BRAIN)),
      RE_uptr(Build(ExtensionType::SensorModule)),
      RE_uptr(Build(ExtensionType::DrillArm)),
      RE_uptr(Build(ExtensionType::GrabbingArm)),
      RE_uptr(Build(ExtensionType::GrabbingArm)),
      RE_uptr(Build(ExtensionType::DriverWheel)),
      RE_uptr(Build(ExtensionType::DriverWheel)),
      RE_uptr(Build(ExtensionType::DriverWheel)),
      RE_uptr(Build(ExtensionType::DriverWheel)),
      RE_uptr(Build(ExtensionType::None))
   });
Nice! I don't understand how that works though because in both cases you have an initializer list of rvalues.
I'm not really sure either, but once I'm finished fixing all the typos in my code, I'm going to do several test runs to make sure the initialization worked properly, i.e. the objects were deep copied.
Topic archived. No new replies allowed.