9

Aggregate initialization requires among other things no user-provided constructors. But std::tuple and std::pair pair have a large set of overloaded constructors. From the point of the core language, are these constructors user-provided or even user-declared ?

With C++17 it will be possible to write (update/clarification: where nocopy is a class that can not be copied or moved, such as std::mutex)

auto get_ensured_rvo_str(){
   return std::pair(std::string(),nocopy());
}

edit: no, it's not possible as explained in the linked to answers and the answer below.

which requires aggregate initialization (for context: Multiple return values (structured bindings) with unmovable types and guaranteed RVO in C++17).

Are tuple and pair backed by special standard language to allow this (in presence of constructors) ? :

20.5.2.1 Construction

... EXPLICIT constexpr tuple(const Types&...);

6 Effects: The constructor initializes each element with the value of the corresponding parameter.

or can we in principle write our own tuple or pair?

Community
  • 1
  • 1
Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
  • The current example doesn't require aggregate initialization. Please provide a relevant example. – Cheers and hth. - Alf Jul 15 '16 at 09:14
  • @songyuanyao, @Alf, My reading of the linked to answers are that it's not possible to initialize uncopyable+unmovable members with an actual constructor like that, and that it's powered by aggregate initialization which is not really a constructor call. Also, clarified that `nocopy` is also unmovable (as in the linked question). – Johan Lundberg Jul 15 '16 at 09:20
  • 1
    If I reading accepted answer correctly, it says that `pair` code will not work. – Revolver_Ocelot Jul 15 '16 at 09:25
  • @Recover_Ocelot. Correct, and in line with the answer by ecatmur. – Johan Lundberg Jul 15 '16 at 09:29

1 Answers1

6

No, there is no support in tuple or pair for passing no-move types to their constructors, and as you've observed there cannot be, since the constructor argument and tuple (or pair) member can be observed to be different objects:

// exposition only
template<class... Us>
tuple(Us&&... us) : values{std::forward<Us>(us)...} {}
              ^^ these
                    ^^^^^^ are different objects to these

You would have to use piecewise construction:

return std::pair<std::string, nocopy>(std::piecewise_construct,
    std::forward_as_tuple(), std::forward_as_tuple());

Matt Calabrese made an interesting point on the std-proposals list that now we have guaranteed RVO it should be possible to write components that accept factories to construct their members effectively inplace:

// hypothetical factory constructor
return std::pair(std::factory_construct,
    [] { return std::string{}; }, [] { return nocopy{}; });

Another possible direction would be to remove the constructors from tuple and pair (or, more realistically, to write workalike components without constructors) and rely on the new extensions to aggregate initialization that should permit aggregate initialization of tuple and pair implemented via multiple-inheritance. Example.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • You are right for sure. It's pretty interesting as it opens up a use case for a plain aggregate without constructors as in the linked to question: `template struct many { T1 a; T2 b; T3 c; }; template many(T1, T2, T3) -> many;`. – Johan Lundberg Jul 15 '16 at 09:34
  • I cannot help but think that the language is becoming too complex to use. With too many overlapping notations. It seems it started with C++14. :( – Cheers and hth. - Alf Jul 15 '16 at 09:39
  • ectamur, as you refined your answer I wrote a follow up question which is quite related to your updates. http://stackoverflow.com/questions/38393302/variadic-struct-and-variadic-template-construction-deduction-guide-in-c17 – Johan Lundberg Jul 15 '16 at 10:04
  • 1
    @Cheersandhth.-Alf: You don't have to know anything about this stuff to use the language. Immobile types not being able to be used with `pair` isn't even new; that's C++98 stuff. If you made your copy constructor go away, it wouldn't work. The only thing that has been made "complex" is that there are now cases where you *can* use immobile objects to initialize aggregates. – Nicol Bolas Jul 15 '16 at 13:11
  • The factory construct bit is awkward. Really, we need a way to efficiently and tersely express "this isn't a Foo, it is instructions on how to construct a Foo in a place of your choosing" as a function argument, *and* to write it on the calling side without having to write a lambda. – Yakk - Adam Nevraumont Jul 16 '16 at 00:04