
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