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