Boost logo

Boost Users :

Subject: Re: [Boost-users] compilation problem and a couple of boost::variant questions
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2012-07-11 16:10:27


On Wed, Jul 11, 2012 at 11:32 AM, Petros <pmamales_at_[hidden]> wrote:

> Hi,
> I am trying to write some operator that multiplies two variants, each one
> containing a vector a zero and a unit, where I am trying to
> use the fact that I know the outcome for multiplying by 0 or by 1.
> The code (very bare bones) below describes how this is done, by:
> _ defining dummy structures of Variant-1, 2
> _ defining a class that contains the instruction for multiplication
> _ defining a class (derived from variant) that contains possible outcomes
> of the multiplication
> _ defining the operator
> (only a few of the possible outcomes are shown)
> Compiling with msvc2010 (intel has similar issues) on win7:
> First here is the code:
>
> #include <boost/variant.hpp>
> using boost::variant;
>
> struct Zero1{ double operator[]( const size_t i ) const { return 0L ; } };
> struct One1{ double operator[]( const size_t i ) const { return 1L ; } };
> struct Zero2{ double operator[]( const size_t i ) const { return 0L ; } };
> struct One2{ double operator[]( const size_t i ) const { return 1L ; } };
> struct Vector1{ double operator[]( const size_t i ) const {return double(
> i ) ; } };
> struct Vector2{ double operator[]( const size_t i ) const {return double(
> 2*i ) ; } };
> struct
> subscript_operator:public boost::static_visitor<double>{
> const size_t i_;
> subscript_operator( const size_t i ):i_(i){}
>
> template<typename _v>
> double operator()( _v const & v ) const {
> return v[i] ;
> }
> };
>
>
> template <typename _V, typename _Z, typename _U>
> class VariantT
> :public variant< _V, _Z, _U >
>

I believe the fact that VariantT<> inherits from boost::variant (combined
with the structure of the boost::variant implementation) is the cause of
the ambiguity in convert_construct referenced below. For example, the
following minimal code produces the same problem:

#include <boost/variant.hpp>

struct X
    : boost::variant< int >
{ };

void main()
{
    X x;
    boost::variant<X> y(x);
}

I'll file a trac ticket against boost::variant; in the meantime, try making
boost::variant a member object rather than a base object.

[...snip remaining code...]

> And here is one of the errors :
>
> boost_1_49_0\boost\variant\variant.hpp(1399): error C2666:
> 'boost::variant<T0_,T1,T2,T3,T4>::convert_construct' : 2 overloads have
> similar conversions
> 1> with
> 1> [
> 1> T0_=MultVarVar<Variant1,Variant2>,
> 1> T1=Zero1,
> 1> T2=One1,
> 1> T3=Variant1,
> 1> T4=Variant2
> 1> ]
> 1>
> c:\_petros\_otc\ext\boost_1_49_0\boost\variant\variant.hpp(1384): could be
> 'void
> boost::variant<T0_,T1,T2,T3,T4>::convert_construct<_V,_Z,_U,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_,boost::detail::variant::void_>(const
> boost::variant<_V,T1,T2> &,long)'
> 1> with
> 1> [
> 1> T0_=MultVarVar<Variant1,Variant2>,
> 1> T1=Zero1,
> 1> T2=One1,
> 1> T3=Variant1,
> 1> T4=Variant2,
> 1> _V=Vector1,
> 1> _Z=Zero1,
> 1> _U=One1
> 1> ]
> 1>
> c:\_petros\_otc\ext\boost_1_49_0\boost\variant\variant.hpp(1315): or
> 'void boost::variant<T0_,T1,T2,T3,T4>::convert_construct<const T>(T
> &,int,boost::mpl::false_)'
> 1> with
> 1> [
> 1> T0_=MultVarVar<Variant1,Variant2>,
> 1> T1=Zero1,
> 1> T2=One1,
> 1> T3=Variant1,
> 1> T4=Variant2,
> 1> T=Variant1
> 1> ]
> 1> while trying to match the argument list '(const Variant1,
> long)'
> 1> c:\_petros\_otc\tests\variant\variant\main.cpp(120) : see
> reference to function template instantiation
> 'boost::variant<T0_,T1,T2,T3,T4>::variant<_V>(const T &)' being compiled
> 1> with
> 1> [
> 1> T0_=MultVarVar<Variant1,Variant2>,
> 1> T1=Zero1,
> 1> T2=One1,
> 1> T3=Variant1,
> 1> T4=Variant2,
> 1> _V=Variant1,
> 1> T=Variant1
> 1> ]
> 1> c:\_petros\_otc\tests\variant\variant\main.cpp(151) : see
> reference to function template instantiation
> 'MultVarVarResult<_V1,_V2>::MultVarVarResult<_V1>(const _V &)' being
> compiled
> 1> with
> 1> [
> 1> _V1=Variant1,
> 1> _V2=Variant2,
> 1> _V=Variant1
> 1> ]
> 1>
>
> Any help on this will be greatly appreciated!
> And the questions:
> What happens if a variant contains two identical template arguments ? when
> I create a (variant) object from one of the two identicals, how does it
> know which template argument I need ?
>

It probably doesn't :) My guess is you'll get some compiler errors based on
ambiguous overloads (distinct but similar to the errors above). I think
your best bet is to preprocess the sequence of value types to remove
duplicate types prior to generating your variant type. You can do this via
Boost.MPL, e.g., the documentation for boost::mpl::set<> [1] has an example
to this effect, and then you may use boost::make_variant_over [2].

> Do I have to write the same code for the specialization of identical _V1
> and _V2?
>

That or complicate the generation of the variant type, as I've described
above.

> Also, am I correct to assume that all this syntax ( element-wise
> static_visitor’s etc) will be optimized away at a release build ?
>

I'm not sure what you're looking to have optimized away. If you mean that
the compiler can somehow deduce at compile time the runtime underlying type
of the variant based on your code in main and somehow optimize away the
runtime dispatching...I guess that's possible, but I wouldn't depend on it
or care, as I can't think of a reason you'd use a boost::variant in such a
scenario other than for testing. On the other hand, if it's impossible to
know the runtime underlying type of the variant, then there's no way to get
around the runtime dispatching.

However, I would expect any decent compiler to collapse all statically
known calls before and after the runtime dispatch, if that's what you're
asking.

HTH,

- Jeff

[1] http://www.boost.org/doc/libs/1_50_0/libs/mpl/doc/refmanual/set.html
[2]
http://www.boost.org/doc/libs/1_50_0/doc/html/variant/tutorial.html#variant.tutorial.over-sequence



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net