Boost logo

Boost :

From: Eric Friedman (ebf_at_[hidden])
Date: 2006-06-07 04:05:52


Hi Yuval,

Thanks for your feedback. In particular, I would like to add support for
in-place construction "sometime" :)

As for operator!= (and operator<=, etc.), while I do think it may be
useful, it raises the question of what requirements variant imposes on
its bounded types. Specifically, adding support for these operators is
not so straightforward as saying operator!= is simply !(*this == rhs).
The idea of operator== and operator< is that if the current bounded type
is the same in both variant instances, then operator overload _for that
type_ will be invoked. To support this same behavior for the other
operators would require adding to the bounded type requirements. See
<http://boost.org/doc/html/variant/reference.html#variant.concepts> for
a refresher on variant's approach to concepts. Maybe this is an
overly-pedantic response on my part, though.

The reason (or at least one of them) that apply_visitor accepts visitors
by reference and not by value is that I had intended to introduce a
dynamic_visitor counterpart to static_visitor in a more general
Boost.Visitor library. Passing by value would interact poorly with
polymorphic dynamic visitors due to slicing. If you are interested, I
believe Boost.Visitor is probably still sitting around in the Boost
Sandbox CVS on Sourceforge.

Variant already supports reference types, at least on modern compilers.
However, references are not assignable, and so as noted in the concepts
documentation for variant, this implies that the resultant variant is
not assignable. To address your comment about boost::optional, then,
variant does not allow rebinding of references.

I'll have to more carefully look at your proposals for additional get
functions to see whether I am convinced of their utility.

Eric

Yuval Ronen wrote:
> Hi Eric!
> It's good to see that you've got back to the list. For a long time now,
> there was no one to answer users' questions and comments, So I'm taking
> this (rare :-) ) opportunity to present my wish list for Boost.Variant.
>
> First of all, I'd like to say that I think it's a great library. I've
> become addicted to it... However, there are some things I think are
> missing.
>
> 1. add operator !=
>
> There's operator==, and adding operator!= would be both easy and useful.
>
> 2. apply_visitor should accept the visitor by value
>
> std algorithms (such as for_each) accept their functors by value, not by
> [const] reference. I think that visitors should be considered as
> variant's equivalent to std functors, and thus be passed by value. This
> will allow me to pass temporary visitor objects, which is a very common
> use case, just as with std functors. It will also allow you to delete
> the two versions of apply_visitor (one taking a reference, one taking a
> const reference), and leave only one.
>
> 3. add support for non-copyable types, a-la Boost.Optional's in-place
> factory
>
> I found myself needing a variant of non-copyable types, and had to
> resort to dynamic allocation to solve it. Luckily for me, it wasn't a
> performance-critical code, so I could live with it. But of course it's
> not optimal...
>
> 4. add more flavours of get()
>
> Currently the get<T>() function has the semantics of "return current
> value only if it is of type implicitly convertible to T". But there are
> other usages, even more useful than this (and if there are other get()s,
> the name of the original get() should be changed to, for example,
> get_implicit).
>
> One of them is "return current value only if it is exactly of type T
> (using type_info)". The function will not compile if T is not any of the
> variant's types. A possible name for it could be get_exact(), but of
> course there might be better names.
>
> Another usage I found useful is when all of the variant's types are
> implicitly convertible to a common T (e.g, they all inherit from T).
> This function will not compile if any of the variant's types can't be
> implicitly convertible to T, but if it does compile, then it ensures it
> can't fail in run-time (in contrast to get_implicit and get_exact, which
> can fail in run-time). A possible name is get_common().
>
> I've attached a file containing my implementation of get_exact and
> get_common, in case you're interested. All the preprocessor magic there
> is beyond my understanding, I just copied it from your code, and hope I
> didn't make any mistakes...
>
> 5. support for reference types
>
> I don't know if Boost.Variant currently supports reference types, nor am
> I certain it should, but it's a possibility...
> There was a debate about Boost.Optional's support for reference types,
> which reached no clear conclusion. Maybe you're familiar with the
> details, but if not, in short, the problem is with code such as
>
> int a = ...;
> int b = ...;
> optional<int &> x; // x in initialized to 'empty'
> x = a; // x is binded to a's reference
> x = b; // is x rebinded to b's reference, or is a assigned the value in b?
>
> The reason I bring it up here, is because I think it's relevant to
> Boost.Variant as well. Variant of reference types will raise the exact
> same questions, which should probably get the exact same answers. IOW,
> both the question of whether to support reference types, and the
> question of how to support them, should apply to both Boost.Optional and
> Boost.Variant uniformly. It's an open issue.
>
> 6. propose it for TR2
>
> For the benefit of all of us...
>
> Thanks again for a great library,
> Yuval
>
>
> ------------------------------------------------------------------------
>
> #ifndef VariantGet_h
> #define VariantGet_h
>
> #include <Utils/Variant.h>
> #include <boost/mpl/assert.hpp>
> #include <boost/mpl/contains.hpp>
>
> namespace boost {
>
> template <typename T>
> struct get_common_visitor : public static_visitor<T>
> {
> T operator()(T t) { return t; }
> };
>
> template <typename T, typename Variant>
> typename add_reference<T>::type get_common(Variant &v)
> {
> get_common_visitor<typename add_reference<T>::type> visitor;
> return v.apply_visitor(visitor);
> }
>
> template <typename T, typename Variant>
> typename add_reference<const T>::type get_common(const Variant &v)
> {
> get_common_visitor<typename add_reference<const T>::type> visitor;
> return v.apply_visitor(visitor);
> }
>
> template <typename T, typename Variant>
> void assert_variant_has_type(const Variant &)
> {
> BOOST_MPL_ASSERT((mpl::contains<typename Variant::types, T>));
> }
>
> template <typename T>
> struct get_exact_visitor : public static_visitor<T>
> {
> T operator()(T t) { return t; }
> };
>
> template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
> inline typename add_pointer<U>::type get_exact(
> boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
> BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
> {
> assert_variant_has_type<U>(*operand);
> typedef typename add_pointer<U>::type U_ptr;
> if (!operand) return static_cast<U_ptr>(0);
> if (operand->type() != typeid(U)) return static_cast<U_ptr>(0);
>
> detail::variant::get_visitor<U> v;
> return operand->apply_visitor(v);
> }
>
> template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
> inline typename add_pointer<const U>::type get_exact(
> const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
> BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
> {
> assert_variant_has_type<U>(*operand);
> typedef typename add_pointer<const U>::type U_ptr;
> if (!operand) return static_cast<U_ptr>(0);
> if (operand->type() != typeid(U)) return static_cast<U_ptr>(0);
>
> detail::variant::get_visitor<const U> v;
> return operand->apply_visitor(v);
> }
>
> template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
> inline typename add_reference<U>::type get_exact(
> boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
> BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
> {
> typedef typename add_pointer<U>::type U_ptr;
> U_ptr result = get_exact<U>(&operand);
>
> if (!result)
> throw bad_get();
> return *result;
> }
>
> template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
> inline typename add_reference<const U>::type get_exact(
> const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
> BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
> {
> typedef typename add_pointer<const U>::type U_ptr;
> U_ptr result = get_exact<const U>(&operand);
>
> if (!result)
> throw bad_get();
> return *result;
> }
>
> } // namespace
>
> #endif /* ! defined VariantGet_h */
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


Boost list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk