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 >
{
public:
    typedef typename _Z zero_type ;
    typedef typename _U unit_type ;
 
    typedef typename VariantT<_V, _Z, _U>    self_type ;
    typedef typename variant< _V, _Z, _U >    variant_type ;
 
    template < typename _V>
    explicit VariantT( _V const & v )
        :variant_type(v)
    {}
    VariantT()
    {}
    VariantT( self_type const & v )
        :variant_type(static_cast<const variant_type&>(v))
    {}
    template < typename _V>
    VariantT & operator = ( _V const & v ) {
        *static_cast<variant_type*>(this) = static_cast<const variant_type&>(v);
        return(*this);
    }
    VariantT & operator = ( self_type const & v ) {
        *static_cast<variant_type*>(this) = v;
        return(*this);
    }
 
    double  operator[]( const size_t i ) const {
        boost::apply_visitor( subscript_operator(i) , *this ) ;
    }
 
    bool isZero() const { return which() == 1 ; }
    bool isUnit() const { return which() == 2 ; }
 
private:
};
 
template < typename _V1, typename _V2 >
class MultVarVar{
public:
    MultVarVar( _V1 const & v1, _V2 const & v2 )
        :v1_(v1),v2_(v2)
    {}
    ~MultVarVar()
    {}
 
    typedef typename _V1::zero_type    zero_type ;
    typedef typename _V1::unit_type    unit_type ;
 
    double  operator[]( const size_t i ) const {
        return
            boost::apply_visitor ( elementwise_visitor( i ), v1, v2 ) ;
    }
 
private:
    _V1 const & v1_ ;
    _V2 const & v2_ ;
 
    struct
        elementwise_visitor
        : public boost::static_visitor< double > {
            const size_t & i_;
    public:
        elementwise_visitor( const size_t & i )
            :i_(i)
        {}
        template <typename _V1, typename _V2 >
        double operator()( _V1 const & v1, _V2 const & v2) const {
            return v1[i_] *  v2[i_] ;
        }
    };
};
 
template < typename _V1, typename _V2 >
class MultVarVarResult
    :public variant<typename MultVarVar<_V1, _V2>, typename MultVarVar<_V1,_V2>::zero_type, typename MultVarVar<_V1,_V2>::unit_type, _V1, _V2 > {
public:
    typedef typename variant<
        typename MultVarVar<_V1, _V2 > ,
        typename MultVarVar<_V1,_V2>::zero_type,
        typename MultVarVar<_V1,_V2>::unit_type,
        _V1,
        _V2 >                                        variant_type;
    typedef typename MultVarVarResult<_V1, _V2>        self_type ;
 
    typedef typename _V1::zero_type zero_type ;
    typedef typename _V1::unit_type unit_type ;
 
    template<typename _V>
    /*explicit*/ MultVarVarResult( _V const & v )
        :variant_type(v)
    {}
    MultVarVarResult( self_type const & v )
        :variant_type(static_cast<const variant_type&>(v))
    {}
    template < typename _V>
    MultVarVarResult & operator = ( _V const & v ) {
        *static_cast<variant_type*>(this) = static_cast<const variant_type&>(v);
        return(*this);
    }
    MultVarVarResult & operator = ( self_type const & v ) {
        *static_cast<variant_type*>(this) = v;
        return(*this);
    }
 
    double  operator[]( const size_t i ) const {
        boost::apply_visitor( subscript_operator(i), *this ) ;
    }
private:
};
 
template <typename _V1, typename _V2>
MultVarVarResult<_V1, _V2> operator * ( _V1 const & v1, _V2 const & v2 ) {
 
    if ( v1.isZero() || v2.isZero() )
        return
            MultVarVarResult<_V1, _V2>( typename MultVarVar<_V1,_V2>::zero_type() ) ;
    if ( v1.isUnit() )
        return
            MultVarVarResult<_V1, _V2>( v2 );
    if ( v2.isUnit() )
        return
            v1 ;
    else
        return
            MultVarVarResult<_V1, _V2>( MultVarVar<_V1, _V2>( v1, v2 ) ) ;
}
 
 
typedef VariantT< Vector1, Zero1, One1 > Variant1;
typedef VariantT< Vector2, Zero2, One2 > Variant2;
 
int main(){
    Variant1 v1;
    v1 = Zero1() ;
    Variant2 v2;
    v2 = One2()  ;
 
    auto x = v1 * v2 ;
 
    return x[0] == double(0) ;
}
 
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 ?
Do I have to write the same code for the specialization of identical _V1 and _V2?
Also, am I correct to assume that all this syntax ( element-wise static_visitor’s etc) will be optimized away at a release build ?
 
TVMIA
 
Petros