2

I'd like a variant contain copies of objects of its type. Somehow it is not working:

struct value
{
};

class json;

using json = ::boost::variant<
  ::std::vector<::std::unique_ptr<json> >,
  ::std::unordered_map<::std::string, ::std::unique_ptr<json> >,
  value
>;

json.hpp:116:2: error: conflicting declaration 'using json = '
 >;
  ^
json.hpp:110:7: error: 'class json' has a previous declaration as 'class json'
 class json;

I know of 2 workarounds already: ::std::unique_ptr<void>, with a custom deleter, as well as the possibility of using ::boost::any instead of the variant, but are these the only ways? The problem with ::boost::any is that I need to enable RTTI for it to work.

user1095108
  • 14,119
  • 9
  • 58
  • 116
  • 2
    Well, the problem is the name conflict. You don't you alias the boost variant as `json_variant` or something? – Marius Bancila Feb 18 '14 at 10:34
  • 1
    You want a `recursive_variant` (… or whatever it's called). Boost has a specific interface for this. For what it's worth, `class json;` means you are going to have a class named `json`, which the typedef-name declared by `using =` is not. – Potatoswatter Feb 18 '14 at 10:38
  • 1
    @user1095108 Not really an SO-worthy answer, but you should read http://www.boost.org/doc/libs/1_55_0/doc/html/variant/tutorial.html#variant.tutorial.recursive – Potatoswatter Feb 18 '14 at 10:43
  • @Potatoswatter I try to overcome the "incomplete type" problem by using `::std::unique_ptr`. If there exists a way to declare `json` some other way, that will compile, I'll accept your answer. – user1095108 Feb 18 '14 at 10:49
  • @user1095108 I'm not personally a Boost user, but see the linked tutorial. `unique_ptr` is a valid, but inefficient workaround. It's better to use the library as it was intended. – Potatoswatter Feb 18 '14 at 10:50
  • @Potatoswatter I am not keen on using boost either, hence I was hoping to see a non-boost workaround. – user1095108 Feb 18 '14 at 10:59
  • @Potatoswatter Look at this, the `recursive_variant_wrapper` uses a `shared_ptr` internally. I think the `unique_ptr` is better! Was a bit worried there. http://stackoverflow.com/questions/4932208/boostvariant-recursive-trouble – user1095108 Feb 19 '14 at 14:20

1 Answers1

1

What about:

struct json : ::boost::variant<
  ::std::vector<::std::unique_ptr<json> >,
  ::std::unordered_map<::std::string, ::std::unique_ptr<json> >,
  value
>
{
  using variant::variant;

  template <typename U>
  json& operator=(U&& u)
  {
    variant::operator=(::std::forward<U>(u));

    return *this;
  }
};

That would be the solution, except it doesn't work for me with g++ (constructing json out of vector fails because of ambiguous constructor call). Construction from a const reference to such a vector works, but not not from a non-const reference. I have no idea why. In addition, unique_ptr doesn't work with boost::variant for me because it's uncopyable (shared_ptr does work).

user1095108
  • 14,119
  • 9
  • 58
  • 116
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • The problem with your solution is that constructors are not inherited, perhaps with inherited constructors... – user1095108 Feb 18 '14 at 10:47
  • Oops, yes, one needs to inherit constructors. Fixing. – n. m. could be an AI Feb 18 '14 at 10:55
  • Could be a bug of the standard itself. Does it demand the copy constructor of a vector to be `SFINAE`d away, if `value_type` is non-copyable? This is causing the problems (which can be remedied by using a `shared_ptr`). – user1095108 Feb 18 '14 at 12:22