0

I have the boost::variant over set of non-default constructible (and maybe even non-moveable/non-copyable and non-copy/move constructible) classes with essentialy different non-default constructor prototypes, as shown below:

#include <boost/variant.hpp>
#include <string>
#include <list>

struct A { A(int) { ; } };
struct B { B(std::string) { ; } };
struct C { C(int, std::string) { ; } };

using V = boost::variant< A const, B const, C const >;
using L = std::list< V >;

int main()
{
    L l;
    l.push_back(A(1)); // an extra copy/move operation
    l.push_back(B("2")); // an extra copy/move operation
    l.push_back(C(3, "3")); // an extra copy/move operation
    l.emplace_back(4);
    l.emplace_back(std::string("5"));
    // l.emplace_back(3, std::string("3")); // error here
    return 0;
}

I expect, that std::list::emplace_back allows me to construct-and-insert (in single operation) new objects (of all the A, B, C types) into list, even if they have T & operator = (T const &) = delete;/T & operator = (T &&) = delete; and T(T const &) = delete;/T(T &&) = delete;. But what should I do, if constructor is a non-conversion one? I.e. have more, than one parameter. Or what I should to do if two different variant's underlying types have ambiguous constructor prototypes? In my opinion, this is the defect of implementation of the boost::variant library in the light of the new features of C++11 standard, if any at all can be applyed to solve the problem.

I specifically asked about std::list and boost::variant in superposition, because they are both internally implement the pimpl idiom in some form, as far as I know (say, boost::variant currently designed by means of temporary heap backup approach).

Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169
  • Do you need a container and `emplace` to see this problem? Presumably the ambiguity issue e.g. can arise just with simple construction of a `boost::variant`. What happens with `V v(3, std::string("3"));`? – Matt Phillips May 16 '13 at 04:20
  • `V v(3, std::string("3"));` leads to an error `no matching function for call to 'boost::variant::variant(int, std::string)'` `note: template argument deduction/substitution failed` `note: candidate expects 1 argument, 2 provided` – Tomilov Anatoliy May 16 '13 at 05:02
  • Your assumption is right. I just illustrated with the example of a real context. `std::list` is not mandatory. – Tomilov Anatoliy May 16 '13 at 05:06
  • `boost::variant` just simply does not have constructor like `template< typename... Args > boost::vector::vector(Args && ...args)` that dispatches arguments to constructor of appropriate underlying type `p = new T(args...);`. – Tomilov Anatoliy May 16 '13 at 05:11

2 Answers2

1

emplace can only call the constructors of the type in question. And boost::variant's constructors only take single objects which are unambiguously convertible to one of the variant's types.

variant doesn't forward parameters arbitrarily to one of its bounded types. It just takes a value. A single value that it will try to convert to one of the bounded types.

So you're going to have to construct an object and then copy that into the variant.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • But what should I do if my type is non-copyable/moveable and non-copy/move constructible? – Tomilov Anatoliy May 16 '13 at 05:13
  • I think, that `std::is_constructible` and some metaprogramming magic can help implement such constructor to `boost::variant` designers. – Tomilov Anatoliy May 16 '13 at 05:16
  • 1
    @Dukales: "*But what should I do if my type is non-copyable/moveable and non-copy/move constructible?*" Then you can't use it in a variant. As for the ability to create such constructors, that may be possible, but it certainly doesn't exist for `boost::variant` *right now*. – Nicol Bolas May 16 '13 at 05:52
1

Assuming you can modify your "C" class, you could give it an additional constructor that takes a single tuple argument.

Nicola Musatti
  • 17,834
  • 2
  • 46
  • 55