
I've been playing around with variant a bit and decided to try to build a data structure for storing json. I came up with several different approaches but none are super-satisfying. I'd like some feedback. (If you need a refresher on what's in json, the front page of http://json.org tells all). In the abstract, json looks like: struct null {}; typedef std::map<std::string, value> object; typedef std::vector<value> array; typedef variant< null, std::string, double, object, array, bool
value;
Naturally, this code isn't legal C++, so I set about making it be. The first thing I tried was to use recursive_wrapper<>, as the documentation implies it is the most flexible way to do this sort of thing. Unfortunately, there's no clean way to reformulate this type in a way that allows recursive_wrapper work, because the type that needs to be wrapped in recursive_wrapper includes "value" in its name, and I can't forward-declare it. The only way to forward-declare a type X, as far as I know, is: struct X; // or class X; So to try to get recursive_wrapper to work, I tried a couple of formulations that started with that, but it turns out that when you do this, you end up not needing recursive_wrapper at all struct value; typedef std::map<std::string, value> object; typedef std::vector<value> array; typedef variant< null, std::string, double, object, array, bool
value_base;
struct value : value_base { value() {}; template <class T> value(T const& x) : base(x) {} // no move; I'm in C++03-land value& operator=(value const& x) { base::operator=(x); return *this; } } }; I don't know if I've missed some things that should be in that "value" class. I know that a recursive variant, in principle, requires a pointer indirection somewhere, so I was wondering if, had I wrapped object and array in recursive_wrapper as below, I would have been adding an unnecessary inefficiency. typedef variant< null, std::string, double, reference_wrapper<object>, reference_wrapper<array>, bool
value_base;
I also wondered whether that would give me different results from typedef std::map<std::string, value> object; typedef std::vector<value> array; typedef variant< null, std::string, double, std::map<std::string, reference_wrapper<value> >, std::vector<reference_wrapper<value> >, bool
value_base;
and which one was better. Does anyone know? I think that should be in the docs. Using recursive_variant_ works out quite nicely, except that it doesn't allow me to separately declare "object" and "array" and re-use them in the definition of "value": typedef boost::make_recursive_variant< null , std::string , double , std::map<std::string, boost::recursive_variant_> , std::vector<boost::recursive_variant_> , bool
::type value;
I also wonder if I'm getting an unnecessary inefficiency in that case. Lastly, what flexibility am I sacrificing by using this approach? -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

On 29/10/2012 04:29 p.m., Dave Abrahams wrote:
In the abstract, json looks like:
struct null {}; typedef std::map<std::string, value> object; typedef std::vector<value> array;
typedef variant< null, std::string, double, object, array, bool
value;
Keep in mind that instantiating a standard container with an incomplete type will yield undefined behavior, and that `variant` has to instantiate both `object` and `array` to know their size. In my own JSON attempt I have used Boost.Containers, which do guarantee defined behavior when instantiated with incomplete types. Agustín K-ballo Bergé.- http://fusionfenix.com

on Mon Oct 29 2012, Agustín K-ballo Bergé <kaballo86-AT-hotmail.com> wrote:
On 29/10/2012 04:29 p.m., Dave Abrahams wrote:
In the abstract, json looks like:
struct null {}; typedef std::map<std::string, value> object; typedef std::vector<value> array;
typedef variant< null, std::string, double, object, array, bool
value;
Keep in mind that instantiating a standard container with an incomplete type will yield undefined behavior, and that `variant` has to instantiate both `object` and `array` to know their size. In my own JSON attempt I have used Boost.Containers, which do guarantee defined behavior when instantiated with incomplete types.
I haven't instantiated anything at that point in the code, though. By the time the containers are instantiated, the types are complete. :-) -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

On 29/10/12 22:15, Dave Abrahams wrote:
on Mon Oct 29 2012, Agustín K-ballo Bergé <kaballo86-AT-hotmail.com> wrote:
On 29/10/2012 04:29 p.m., Dave Abrahams wrote:
In the abstract, json looks like:
struct null {}; typedef std::map<std::string, value> object; typedef std::vector<value> array;
typedef variant< null, std::string, double, object, array, bool > value;
Keep in mind that instantiating a standard container with an incomplete type will yield undefined behavior, and that `variant` has to instantiate both `object` and `array` to know their size. In my own JSON attempt I have used Boost.Containers, which do guarantee defined behavior when instantiated with incomplete types.
I haven't instantiated anything at that point in the code, though.
According to the code you provided, you do instantiate the std::vector class template with an incomplete type in both the no_wrapper and wrapper cases.

on Mon Oct 29 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
Keep in mind that instantiating a standard container with an incomplete type will yield undefined behavior, and that `variant` has to instantiate both `object` and `array` to know their size. In my own JSON attempt I have used Boost.Containers, which do guarantee defined behavior when instantiated with incomplete types.
I haven't instantiated anything at that point in the code, though.
According to the code you provided, you do instantiate the std::vector class template with an incomplete type in both the no_wrapper and wrapper cases.
You're right :-( -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

on Mon Oct 29 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 29/10/12 22:15, Dave Abrahams wrote:
on Mon Oct 29 2012, Agustín K-ballo Bergé <kaballo86-AT-hotmail.com> wrote:
On 29/10/2012 04:29 p.m., Dave Abrahams wrote:
In the abstract, json looks like:
struct null {}; typedef std::map<std::string, value> object; typedef std::vector<value> array;
typedef variant< null, std::string, double, object, array, bool > value;
Keep in mind that instantiating a standard container with an incomplete type will yield undefined behavior, and that `variant` has to instantiate both `object` and `array` to know their size. In my own JSON attempt I have used Boost.Containers, which do guarantee defined behavior when instantiated with incomplete types.
I haven't instantiated anything at that point in the code, though.
According to the code you provided, you do instantiate the std::vector class template with an incomplete type in both the no_wrapper and wrapper cases.
Actually, I think the wrapper case is perfectly legal... and I can prove it. The following compiles: --8<---------------cut here---------------start------------->8--- namespace wrapper { struct value; template <class T, class U> struct mymap : std::map<T,U> { enum { _size = sizeof(T)+sizeof(U) }; // error if T or U are incomplete }; typedef mymap<std::string, value> object; template <class T> struct myvec : std::vector<T> { enum { _size = sizeof(T) }; // error if T or U are incomplete }; typedef myvec<value> array; typedef variant< null, std::string, double, recursive_wrapper<object>, recursive_wrapper<array>, bool
value_base;
struct value : value_base { value() {}; template <class T> value(T const& x) : value_base(x) {} // no move; I'm in C++03-land value& operator=(value const& x) { value_base const& x_ = x; value_base::operator=(x_); return *this; } }; } wrapper::value x; --8<---------------cut here---------------end--------------->8--- -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

On 31/10/12 19:02, Dave Abrahams wrote:
namespace wrapper { struct value;
template <class T, class U> struct mymap : std::map<T,U> { enum { _size = sizeof(T)+sizeof(U) }; // error if T or U are incomplete }; typedef mymap<std::string, value> object;
This line instantiates the declaration of std::map<std::string, value>, but not its definition, which is why you don't get any error (doing those sizeofs inside the declaration itself will yield errors though of course). I'm no expert at standardese but it seems class template instantiation usually refers to instantiating the definition, which would mean that this is indeed allowed.

on Fri Nov 02 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 31/10/12 19:02, Dave Abrahams wrote:
namespace wrapper { struct value;
template <class T, class U> struct mymap : std::map<T,U> { enum { _size = sizeof(T)+sizeof(U) }; // error if T or U are incomplete }; typedef mymap<std::string, value> object;
This line instantiates the declaration of std::map<std::string, value>,
If by the declaration you mean template <class K, class V, class C, class A> struct map; then yes.
but not its definition, which is why you don't get any error (doing those sizeofs inside the declaration itself will yield errors though of course).
You mean like this? --8<---------------cut here---------------start------------->8--- template <class T, class U, unsigned n = sizeof(T)+sizeof(U)> struct mymap : std::map<T,U> {}; --8<---------------cut here---------------end--------------->8--- If so, then, as you say... "of course."
I'm no expert at standardese but it seems class template instantiation usually refers to instantiating the definition, which would mean that this is indeed allowed.
-- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

on Mon Oct 29 2012, Dave Abrahams <dave-AT-boostpro.com> wrote:
I've been playing around with variant a bit and decided to try to build a data structure for storing json. I came up with several different approaches but none are super-satisfying. I'd like some feedback. (If you need a refresher on what's in json, the front page of http://json.org tells all).
I got *some* answers to my questions by experimentation: https://gist.github.com/3976374 Output: size of objects: 48, 48, 48 size of arrays: 24, 24, 24 size of variants: 56, 16, 16 What I learned is that using either recursive_wrapper or recursive_variant_ *does* seem to introduce an indirection even if one isn't needed. I also learned that 8 bytes are used for a discriminant on my x64 system, which I'll grudgingly admit might be the best we can do. But only grudgingly. Comments on other questions in that message are still appreciated. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

Dave Abrahams wrote:
I've been playing around with variant a bit and decided to try to build a data structure for storing json.
Hmmm - did you consider making a serialization library "archive" for json files? I know one has been submitted, I've never done anything with it though. Robert Ramey

on Mon Oct 29 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
Dave Abrahams wrote:
I've been playing around with variant a bit and decided to try to build a data structure for storing json.
Hmmm - did you consider making a serialization library "archive" for json files?
No; I'm just experimenting with variant at this point. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

On 29/10/2012 06:10 p.m., Robert Ramey wrote:
Hmmm - did you consider making a serialization library "archive" for json files?
I know one has been submitted, I've never done anything with it though.
I would love to see that "archive" implementation. I wanted to implement one myself but didn't know where to begin. Is this code available somewhere? Agustín K-ballo Bergé.- http://fusionfenix.com

On 29/10/12 20:29, Dave Abrahams wrote:
Using recursive_variant_ works out quite nicely, except that it doesn't allow me to separately declare "object" and "array" and re-use them in the definition of "value":
typedef boost::make_recursive_variant< null , std::string , double , std::map<std::string, boost::recursive_variant_> , std::vector<boost::recursive_variant_> , bool
::type value;
I'd use this method, it's clearly the cleanest. I don't understand what's your problem with it.

on Mon Oct 29 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 29/10/12 20:29, Dave Abrahams wrote:
Using recursive_variant_ works out quite nicely, except that it doesn't allow me to separately declare "object" and "array" and re-use them in the definition of "value":
typedef boost::make_recursive_variant< null , std::string , double , std::map<std::string, boost::recursive_variant_> , std::vector<boost::recursive_variant_> , bool
::type value;
I'd use this method, it's clearly the cleanest. I don't understand what's your problem with it.
As I had feared, and as http://news.gmane.org/find-root.php?message_id=%3cm2objlggaw.fsf%40pluto.lua... demonstrates, extra dynamic allocations will be used to store maps and vectors (or anything at all?) in the variant. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

On 29/10/12 22:33, Dave Abrahams wrote:
on Mon Oct 29 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 29/10/12 20:29, Dave Abrahams wrote:
Using recursive_variant_ works out quite nicely, except that it doesn't allow me to separately declare "object" and "array" and re-use them in the definition of "value":
typedef boost::make_recursive_variant< null , std::string , double , std::map<std::string, boost::recursive_variant_> , std::vector<boost::recursive_variant_> , bool >::type value;
I'd use this method, it's clearly the cleanest. I don't understand what's your problem with it.
As I had feared, and as http://news.gmane.org/find-root.php?message_id=%3cm2objlggaw.fsf%40pluto.lua... demonstrates, extra dynamic allocations will be used to store maps and vectors (or anything at all?) in the variant.
Why not fix the implementation then instead of writing hacks? Of course, the code of variant is horrible enough to make it very difficult to do anything with it.

AMDG On 10/29/2012 02:59 PM, Mathias Gaunard wrote:
On 29/10/12 22:33, Dave Abrahams wrote:
As I had feared, and as http://news.gmane.org/find-root.php?message_id=%3cm2objlggaw.fsf%40pluto.lua...
demonstrates, extra dynamic allocations will be used to store maps and vectors (or anything at all?) in the variant.
Why not fix the implementation then instead of writing hacks?
There's no automatic way around dynamic allocation. a) vector<variant<...> > requires variant to be complete. b) variant<std::vector<...> > requires vector to be complete because it needs to know the sizeof(std::vector<...>). The only way to break the cyclic dependency is to make the size of variant not depend on the size of the vector.
Of course, the code of variant is horrible enough to make it very difficult to do anything with it.
In Christ, Steven Watanabe

on Mon Oct 29 2012, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
AMDG
On 10/29/2012 02:59 PM, Mathias Gaunard wrote:
On 29/10/12 22:33, Dave Abrahams wrote:
As I had feared, and as http://news.gmane.org/find-root.php?message_id=%3cm2objlggaw.fsf%40pluto.lua...
demonstrates, extra dynamic allocations will be used to store maps and vectors (or anything at all?) in the variant.
Why not fix the implementation then instead of writing hacks?
There's no automatic way around dynamic allocation.
a) vector<variant<...> > requires variant to be complete. b) variant<std::vector<...> > requires vector to be complete because it needs to know the sizeof(std::vector<...>).
The only way to break the cyclic dependency is to make the size of variant not depend on the size of the vector.
Yup. We "know" the indirection is already there in std::vector/map, but we can't use it. Yes, I realize that the implementation is free to do the small object optimization, which *could* blow our assumption that the indirection isn't needed... but in practice, it doesn't. Tant pis. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

AMDG On 10/30/2012 07:11 AM, Dave Abrahams wrote:
on Mon Oct 29 2012, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
The only way to break the cyclic dependency is to make the size of variant not depend on the size of the vector.
Yup. We "know" the indirection is already there in std::vector/map, but we can't use it. Yes, I realize that the implementation is free to do the small object optimization,
Not really. "no swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped." (C++11 23.2.1.10) I don't know of any way to implement this with the small object optimization.
which *could* blow our assumption that the indirection isn't needed... but in practice, it doesn't. Tant pis.
I believe that I've seen tickets in trac indicating that at least one STL implementation checks that the element type is complete, so we can't even assume that it works in practice. In Christ, Steven Watanabe

Steven Watanabe wrote:
I believe that I've seen tickets in trac indicating that at least one STL implementation checks that the element type is complete, so we can't even assume that it works in practice.
The variant could perhaps define some dummy complete type X and allocate space for vector<X>, betting on the fact that vector<Y> would have the same size. And if it doesn't, well, the heap is it then.

on Wed Oct 31 2012, "Peter Dimov" <lists-AT-pdimov.com> wrote:
Steven Watanabe wrote:
I believe that I've seen tickets in trac indicating that at least one STL implementation checks that the element type is complete, so we can't even assume that it works in practice.
The variant could perhaps define some dummy complete type X and allocate space for vector<X>, betting on the fact that vector<Y> would have the same size. And if it doesn't, well, the heap is it then.
Yeah, I thought of that. Very interesting problem space in the end. I'm slightly tempted to think about a rewrite. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

2012/10/31 Dave Abrahams <dave@boostpro.com>
on Wed Oct 31 2012, "Peter Dimov" <lists-AT-pdimov.com> wrote:
Steven Watanabe wrote:
I believe that I've seen tickets in trac indicating that at least one STL implementation checks that the element type is complete, so we can't even assume that it works in practice.
The variant could perhaps define some dummy complete type X and allocate space for vector<X>, betting on the fact that vector<Y> would have the same size. And if it doesn't, well, the heap is it then.
Yeah, I thought of that. Very interesting problem space in the end. I'm slightly tempted to think about a rewrite.
May be it would be better to write a metafunction: template <class T> size_forward { enum ENUM{value = sizeof(T)}; }; User is free to specialize it, so Boost.Variant can use it to get sizes of types (instead of directly calling to sizeof(T)) Specialization for your case will be: template <> struct size_forward<vector<Y>> { enum ENUM{value = sizeof(vector<X>)}; }; I think that such metafunction could be widely used (for example in Boost.Optional) -- Best regards, Antony Polukhin

on Wed Oct 31 2012, Antony Polukhin <antoshkka-AT-gmail.com> wrote:
2012/10/31 Dave Abrahams <dave@boostpro.com>
on Wed Oct 31 2012, "Peter Dimov" <lists-AT-pdimov.com> wrote:
Steven Watanabe wrote:
I believe that I've seen tickets in trac indicating that at least one STL implementation checks that the element type is complete, so we can't even assume that it works in practice.
The variant could perhaps define some dummy complete type X and allocate space for vector<X>, betting on the fact that vector<Y> would have the same size. And if it doesn't, well, the heap is it then.
Yeah, I thought of that. Very interesting problem space in the end. I'm slightly tempted to think about a rewrite.
May be it would be better to write a metafunction:
template <class T> size_forward { enum ENUM{value = sizeof(T)}; };
User is free to specialize it, so Boost.Variant can use it to get sizes of types (instead of directly calling to sizeof(T))
Specialization for your case will be:
template <> struct size_forward<vector<Y>> { enum ENUM{value = sizeof(vector<X>)}; };
I think that such metafunction could be widely used (for example in Boost.Optional)
As far as I can tell, putting sizeof() inside a layer of template instantiation doesn't solve anything. But maybe I'm missing something. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

On Thu, 1 Nov 2012, Dave Abrahams wrote:
on Wed Oct 31 2012, Antony Polukhin <antoshkka-AT-gmail.com> wrote:
May be it would be better to write a metafunction:
template <class T> size_forward { enum ENUM{value = sizeof(T)}; };
User is free to specialize it, so Boost.Variant can use it to get sizes of types (instead of directly calling to sizeof(T))
Specialization for your case will be:
template <> struct size_forward<vector<Y>> { enum ENUM{value = sizeof(vector<X>)}; };
I think that such metafunction could be widely used (for example in Boost.Optional)
As far as I can tell, putting sizeof() inside a layer of template instantiation doesn't solve anything. But maybe I'm missing something.
I think he is replacing sizeof(vector<incomplete>) with sizeof(vector<int>) (as suggested a few messages back), not just hiding sizeof in templates. -- Marc Glisse

on Thu Nov 01 2012, Marc Glisse <marc.glisse-AT-inria.fr> wrote:
On Thu, 1 Nov 2012, Dave Abrahams wrote:
on Wed Oct 31 2012, Antony Polukhin <antoshkka-AT-gmail.com> wrote:
May be it would be better to write a metafunction:
template <class T> size_forward { enum ENUM{value = sizeof(T)}; };
User is free to specialize it, so Boost.Variant can use it to get sizes of types (instead of directly calling to sizeof(T))
Specialization for your case will be:
template <> struct size_forward<vector<Y>> { enum ENUM{value = sizeof(vector<X>)}; };
I think that such metafunction could be widely used (for example in Boost.Optional)
As far as I can tell, putting sizeof() inside a layer of template instantiation doesn't solve anything. But maybe I'm missing something.
I think he is replacing sizeof(vector<incomplete>) with sizeof(vector<int>) (as suggested a few messages back), not just hiding sizeof in templates.
Yeah... problem is, that might turn out to be wrong. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

On 01/11/12 14:37, Dave Abrahams wrote:
As far as I can tell, putting sizeof() inside a layer of template instantiation doesn't solve anything. But maybe I'm missing something.
The idea would be that the user of variant<T0, T1, ..., Tn> would be able to provide incomplete types Ti if size_forward<Ti> is specialized.

on Fri Nov 02 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 01/11/12 14:37, Dave Abrahams wrote:
As far as I can tell, putting sizeof() inside a layer of template instantiation doesn't solve anything. But maybe I'm missing something.
The idea would be that the user of variant<T0, T1, ..., Tn> would be able to provide incomplete types Ti if size_forward<Ti> is specialized.
I suppose one could arrange for a later compilation error should the size turn out to be wrong. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

2012/11/2 Dave Abrahams <dave@boostpro.com>:
on Fri Nov 02 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 01/11/12 14:37, Dave Abrahams wrote:
As far as I can tell, putting sizeof() inside a layer of template instantiation doesn't solve anything. But maybe I'm missing something.
The idea would be that the user of variant<T0, T1, ..., Tn> would be able to provide incomplete types Ti if size_forward<Ti> is specialized.
Yes, that is what I mean.
I suppose one could arrange for a later compilation error should the size turn out to be wrong.
Yes, BOOST_STATIC_ASSERT((size_forward<Ti>::value == sizeof(Ti))); must be put somevere in the code. But, sizeof() for incomplete types is not the only problem. It looks like we would also need has_nothrow_constructor_forward<Ti> (and may be some more "_forward" versions of meta functions), because Boost.Variant uses some heuristics to detect fallback_type and dynamic allocation requirements. Here is a small example: struct some_pod_t; template <> struct size_forward<some_pod_t> {enum ENU {value = 1}; }; struct some_nonpod_type { some_nonpod_type(); some_nonpod_type(const some_nonpod_type&){} some_nonpod_type& operator=(const some_nonpod_type&){} }; // Will not detect fallback type or will be a compilation failure in has_nothrow_constructor<some_pod_t> boost::variant<some_nonpod_type, some_pod_t> v; // If there was no compilation error... struct some_pod_t {}; // Will detect some_pod_t as fallback type boost::variant<some_nonpod_type, some_pod_t> v2; ... v = v2; // Strange things may happen -- Best regards, Antony Polukhin

On Tue, Oct 30, 2012 at 10:16 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
Not really.
"no swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped." (C++11 23.2.1.10)
I don't know of any way to implement this with the small object optimization.
"Challenge accepted"? Well, depends what is meant by pointers and references. Actual pointers and references, or vector<>::pointer_type, etc? Because, at least for iterators, you could keep a list of outstanding iterators and update them during swap. Typically not a good idea, but possible. Same for pointer/reference if they only need to be pointer-like and reference-like. Also, I suppose my vector could have small object optimization until a pointer/reference was taken. Again, probably not a brilliant plan... Tony

on Mon Oct 29 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 29/10/12 22:33, Dave Abrahams wrote:
on Mon Oct 29 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 29/10/12 20:29, Dave Abrahams wrote:
Using recursive_variant_ works out quite nicely, except that it doesn't allow me to separately declare "object" and "array" and re-use them in the definition of "value":
typedef boost::make_recursive_variant< null , std::string , double , std::map<std::string, boost::recursive_variant_> , std::vector<boost::recursive_variant_> , bool >::type value;
I'd use this method, it's clearly the cleanest. I don't understand what's your problem with it.
As I had feared, and as http://news.gmane.org/find-root.php?message_id=%3cm2objlggaw.fsf%40pluto.lua... demonstrates, extra dynamic allocations will be used to store maps and vectors (or anything at all?) in the variant.
I should also point out that it might be putting the indirection in the "wrong" place. having the recursive_wrapper around the whole map or vector is clearly more efficient than having it around (part of) their elements.
Why not fix the implementation then instead of writing hacks?
I realized it's not completely fixable as Steven points out. I actually did think of trying to do something about other issues, https://svn.boost.org/trac/boost/ticket/7601, but...
Of course, the code of variant is horrible enough to make it very difficult to do anything with it.
...exactly. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost
participants (9)
-
Agustín K-ballo Bergé
-
Antony Polukhin
-
Dave Abrahams
-
Gottlob Frege
-
Marc Glisse
-
Mathias Gaunard
-
Peter Dimov
-
Robert Ramey
-
Steven Watanabe