compilation problem and a couple of boost::variant questions
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
On 07/11/12 13:32, Petros wrote:
Hi, I am trying to write some operator that multiplies two variants, each [snip] First here is the code:
#include
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
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
(v)) {} template < typename _V> VariantT & operator = ( _V const & v ) { *static_cast (this) = static_cast (v); return(*this); } VariantT & operator = ( self_type const & v ) { *static_cast (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
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>::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
(v)) {} template < typename _V> MultVarVarResult & operator = ( _V const & v ) { *static_cast (this) = static_cast (v); return(*this); } MultVarVarResult & operator = ( self_type const & v ) { *static_cast (this) = v; return(*this); } double operator[]( const size_t i ) const { boost::apply_visitor( subscript_operator(i), *this ) ; } private: };
template
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) ; }
[snip] The attached contains a few minor corrections; however, there's still a few I don't know about. In particular, there's the shadowing. Maybe you have some idea how to correct some of the remaining problems. Compilation with gcc4.8 shows errors shown in 2nd attachment. -regards Larry
Thank you Larry, tried it out with the same error messages. All the Best, Petros -----Original Message----- From: Larry Evans Sent: Wednesday, July 11, 2012 4:04 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] compilation problem and a couple ofboost::variant questions On 07/11/12 13:32, Petros wrote:
Hi, I am trying to write some operator that multiplies two variants, each [snip] First here is the code:
#include
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
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
(v)) {} template < typename _V> VariantT & operator = ( _V const & v ) { *static_cast (this) = static_cast (v); return(*this); } VariantT & operator = ( self_type const & v ) { *static_cast (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
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>::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
(v)) {} template < typename _V> MultVarVarResult & operator = ( _V const & v ) { *static_cast (this) = static_cast (v); return(*this); } MultVarVarResult & operator = ( self_type const & v ) { *static_cast (this) = v; return(*this); } double operator[]( const size_t i ) const { boost::apply_visitor( subscript_operator(i), *this ) ; } private: };
template
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) ; }
[snip] The attached contains a few minor corrections; however, there's still a few I don't know about. In particular, there's the shadowing. Maybe you have some idea how to correct some of the remaining problems. Compilation with gcc4.8 shows errors shown in 2nd attachment. -regards Larry _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On 07/11/12 16:24, Petros wrote:
Thank you Larry, tried it out with the same error messages. All the Best, Petros
But what about the shadowing? I'm uncertain what you're intentions are for: template < typename _V> explicit VariantT( _V const & v ) :variant_type(v) {} so you'll have to provide the correction. -regards, Larry
On Wed, Jul 11, 2012 at 11:32 AM, Petros
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
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
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
And here is one of the errors :
boost_1_49_0\boost\variant\variant.hpp(1399): error C2666: 'boost::variant
::convert_construct' : 2 overloads have similar conversions 1> with 1> [ 1> T0_=MultVarVar , 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 ::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 , 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 ::convert_construct<const T>(T &,int,boost::mpl::false_)' 1> with 1> [ 1> T0_=MultVarVar , 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 ::variant<_V>(const T &)' being compiled 1> with 1> [ 1> T0_=MultVarVar , 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....
Jeff,
Thank you very much for responding.
I tried containment, instead of inheritance, as you suggest, getting the same error messages.
Tried to substitute the templated c/tors/assignment operators but w/out (good) result.
I believe that the real issue is that the c/tor in variant is templated.
As far as the identical template arguments for variant, maybe a c/tor with the (0-based ?) type could be of use.
Imagine the amount of complexity that is generated, by trying to write template expressions where arguments
may just happen to be the same (of course, I know nothing on the implementation details of variant – so I may well be waaaay off )
Finally, I am only interested about compile time “polymorphism”. The real motivation of all this is that, I have expressions that can sometimes generate
a unit/zero vector (like in a Monte-Carlo simulation) and want to maintain a uniform interface across expressions that generate this “vector” (hence the variant)
-nothing terribly original )
So, do you think that this construct will be optimized away at compile time ( for me the variants can as well be no-re-assignable) ?
Thank you very much for taking the trouble to look into it,
Petros
PS: google search indicated that this kind of problem was attributed to the msvc compiler misusing the base templated c/tors. However, the result is identical with the intel
12.1 compiler (not that it cannot suffer from the same issue).
From: Jeffrey Lee Hellrung, Jr.
Sent: Wednesday, July 11, 2012 4:10 PM
To: boost-users@lists.boost.org
Subject: Re: [Boost-users] compilation problem and a couple ofboost::variant questions
On Wed, Jul 11, 2012 at 11:32 AM, Petros
[Please avoid top-posting;
http://www.boost.org/community/policy.html#quoting]
On Wed, Jul 11, 2012 at 2:10 PM, Petros
Jeff, Thank you very much for responding. I tried containment, instead of inheritance, as you suggest, getting the same error messages.
Ummm...are you sure? The following compiles fine for me on MSVC9 (note
copious additional fixes which did not include fixing the template
parameter shadowing):
--------
#include
Tried to substitute the templated c/tors/assignment operators but w/out (good) result.
What do you mean? I believe that the real issue is that the c/tor in variant is templated.
The problem isn't the templatization per se, it's the unconstrainedness of the templated constructor (IIRC) :/
As far as the identical template arguments for variant, maybe a c/tor with the (0-based ?) type could be of use.
You mean the first type in the sequence of value types that is convertible from the argument? That's possible, but I don't believe boost::variant presently attempts to do that. You can always try!
Imagine the amount of complexity that is generated, by trying to write template expressions where arguments may just happen to be the same (of course, I know nothing on the implementation details of variant – so I may well be waaaay off [image: Winking smile])
I don't think it's too difficult to write a metafunction that generates the desired variant, and all the complexity would be isolated to that metafunction. Finally, I am only interested about compile time “polymorphism”.
Hmmm...then why are you using variant?
The real motivation of all this is that, I have expressions that can sometimes generate a unit/zero vector (like in a Monte-Carlo simulation) and want to maintain a uniform interface across expressions that generate this “vector” (hence the variant) -nothing terribly original [image: Winking smile])
Well, variant essentially erases the type of the object it's constructed with, so you're effectively using runtime polymorphism (though of a more controlled nature than boost::any or virtual functions). I don't know enough about the particulars of your application based on your description above to know if that's appropriate.
So, do you think that this construct will be optimized away at compile time ( for me the variants can as well be no-re-assignable) ?
I still don't know what you want optimized away. Thank you very much for taking the trouble to look into it,
Petros
PS: google search indicated that this kind of problem was attributed to the msvc compiler misusing the base templated c/tors. However, the result is identical with the intel 12.1 compiler (not that it cannot suffer from the same issue).
It's a related but distinct issue in this case.
*From:* Jeffrey Lee Hellrung, Jr.
*Sent:* Wednesday, July 11, 2012 4:10 PM *To:* boost-users@lists.boost.org *Subject:* Re: [Boost-users] compilation problem and a couple ofboost::variant questions On Wed, Jul 11, 2012 at 11:32 AM, Petros
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
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
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
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
::convert_construct' : 2 overloads have similar conversions 1> with 1> [ 1> T0_=MultVarVar , 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 ::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 , 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 ::convert_construct<const T>(T &,int,boost::mpl::false_)' 1> with 1> [ 1> T0_=MultVarVar , 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 ::variant<_V>(const T &)' being compiled 1> with 1> [ 1> T0_=MultVarVar , 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....
Hi Jeffrey, As I said in another note, it works OK if I do the containment in VariantT. >> The problem isn't the templatization per se, it's the unconstrainedness of the templated constructor (IIRC) :/ Aggree on the template issue “problem”. Maybe there should be a macro with explicit type instantiations. >> You mean the first type in the sequence of value types that is convertible from the argument? That's possible, but I don't believe boost::variant presently attempts to do that. You can always try! Or, maybe can’t ) (I really have a user’s knowledge/attitude to variant). >> I don't think it's too difficult to write a metafunction that generates the desired variant, and all the complexity would be isolated to that metafunction. Aggreed >> Hmmm...then why are you using variant? Because I need a single type as an output from my various templates. Say you are solving a PDE. And your various PDE classes contain (coefficient) functions of all kinds ( contstants, zeros etc.) Then I want to have a unique type as an output. A variant seemed like a good idea. The type of the function is known at compile time. I just don’t want to carry around O(N^2) types where N the dimensionality of the PDE - and this is just for the cross terms. >>Well, variant essentially erases the type of the object it's constructed with, so you're effectively using runtime polymorphism (though of a more controlled nature than boost::any or virtual functions). I don't know enough about the particulars of your application based on your description above to know if that's appropriate. Here is a problem to understand what I am thinking of (only for info purposes, no purpose of cluttering you): Say, I have a vector Monte-Carlo engine that advances like V(t_dt) = m*dt * sigma*Fi*zeta*random where now m, sigma, Fi, zeta can be zero or one and have various classes that produce them. I want to have a single class for the advancement (actually there are various different classes dependent on the numerical method). Now, I can use expression templates for them, but there are significant gains if I know that certain type are fixed (say, m = 0 and/or zeta = 1 ). This is why I want to ba able to have these functions in a controlled manner (they are only a few of those, so a variant seems natutral. The same with a PDE example. What I really need is some variant type that encapsulates what I described above. The number of calls to the subscript operator is going to be in the millions. (btw this is what I call opimized) If this is not it, I should better change gear. Is this what you are saying ? (I could always use an mpl:: vector of types but the whole mgmt would be tedious) Thank you very-very much for all your help. Apologies for my earlier miss-communication. All the best, Petros PS: No offense to anyone, but the documentation is a bit obscure. I think there would be a certain benefit, if in the documentation there was some info on implementation issues, to allow people to make more educated decisions. Maybe it is my fault, but after having spent some time with it, I still do not know what is contained in the data structure ( copies, references/pointers-to-external objects, who knows), what are the guarantees of compile-time variant etc. (Maybe, in the end, I am using the wrong data structure and really what I need is a variant of types ! ). From: Jeffrey Lee Hellrung, Jr. Sent: Wednesday, July 11, 2012 5:39 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] compilation problem and a couple ofboost::variantquestions [Please avoid top-posting; http://www.boost.org/community/policy.html#quoting] On Wed, Jul 11, 2012 at 2:10 PM, Petroswrote: Jeff, Thank you very much for responding. I tried containment, instead of inheritance, as you suggest, getting the same error messages. Ummm...are you sure? The following compiles fine for me on MSVC9 (note copious additional fixes which did not include fixing the template parameter shadowing): -------- #include 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 { const size_t i_; subscript_operator( const size_t i ):i_(i){} template double operator()( _v const & v ) const { //return v[i] ; return v[i_] ; } }; template 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) :v_(v) {} VariantT() {} //VariantT( self_type const & v ) // :variant_type(static_cast (v)) //{} template < typename _V> VariantT & operator = ( _V const & v ) { //*static_cast (this) = static_cast (v); v_ = v; return(*this); } //VariantT & operator = ( self_type const & v ) { // *static_cast (this) = v; // return(*this); //} double operator[]( const size_t i ) const { //boost::apply_visitor( subscript_operator(i) , *this ) ; return boost::apply_visitor( subscript_operator(i), v_ ) ; } //bool isZero() const { return which() == 1 ; } bool isZero() const { return v_.which() == 1 ; } //bool isUnit() const { return which() == 2 ; } bool isUnit() const { return v_.which() == 2 ; } template< class Visitor > typename Visitor::result_type apply_visitor(Visitor visitor) const { return boost::apply_visitor(visitor, v_); } private: variant_type v_; }; 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 ) ; 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 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>::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 /*explicit*/ MultVarVarResult( _V const & v ) :variant_type(v) {} MultVarVarResult( self_type const & v ) :variant_type(static_cast (v)) {} template < typename _V> MultVarVarResult & operator = ( _V const & v ) { *static_cast (this) = static_cast (v); return(*this); } MultVarVarResult & operator = ( self_type const & v ) { *static_cast (this) = v; return(*this); } double operator[]( const size_t i ) const { //boost::apply_visitor( subscript_operator(i), *this ) ; return boost::apply_visitor( subscript_operator(i), *this ) ; } private: }; template 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 ; MultVarVarResult< Variant1, Variant2 > x = v1 * v2; return x[0] == double(0) ; } -------- Tried to substitute the templated c/tors/assignment operators but w/out (good) result. What do you mean? I believe that the real issue is that the c/tor in variant is templated. The problem isn't the templatization per se, it's the unconstrainedness of the templated constructor (IIRC) :/ As far as the identical template arguments for variant, maybe a c/tor with the (0-based ?) type could be of use. You mean the first type in the sequence of value types that is convertible from the argument? That's possible, but I don't believe boost::variant presently attempts to do that. You can always try! Imagine the amount of complexity that is generated, by trying to write template expressions where arguments may just happen to be the same (of course, I know nothing on the implementation details of variant – so I may well be waaaay off ) I don't think it's too difficult to write a metafunction that generates the desired variant, and all the complexity would be isolated to that metafunction. Finally, I am only interested about compile time “polymorphism”. Hmmm...then why are you using variant? The real motivation of all this is that, I have expressions that can sometimes generate a unit/zero vector (like in a Monte-Carlo simulation) and want to maintain a uniform interface across expressions that generate this “vector” (hence the variant) -nothing terribly original ) Well, variant essentially erases the type of the object it's constructed with, so you're effectively using runtime polymorphism (though of a more controlled nature than boost::any or virtual functions). I don't know enough about the particulars of your application based on your description above to know if that's appropriate. So, do you think that this construct will be optimized away at compile time ( for me the variants can as well be no-re-assignable) ? I still don't know what you want optimized away. Thank you very much for taking the trouble to look into it, Petros PS: google search indicated that this kind of problem was attributed to the msvc compiler misusing the base templated c/tors. However, the result is identical with the intel 12.1 compiler (not that it cannot suffer from the same issue). It's a related but distinct issue in this case. From: Jeffrey Lee Hellrung, Jr. Sent: Wednesday, July 11, 2012 4:10 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] compilation problem and a couple ofboost::variant questions On Wed, Jul 11, 2012 at 11:32 AM, Petros 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 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 { const size_t i_; subscript_operator( const size_t i ):i_(i){} template double operator()( _v const & v ) const { return v[i] ; } }; template 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 struct X : boost::variant< int > { }; void main() { X x; boost::variant 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 ::convert_construct' : 2 overloads have similar conversions 1> with 1> [ 1> T0_=MultVarVar , 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 ::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 , 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 ::convert_construct (T &,int,boost::mpl::false_)' 1> with 1> [ 1> T0_=MultVarVar , 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 ::variant<_V>(const T &)' being compiled 1> with 1> [ 1> T0_=MultVarVar , 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 mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Wed, Jul 11, 2012 at 4:38 PM, Petroswrote: [...] > >> You mean the first type in the sequence of value types that is > convertible from the argument? That's possible, but I don't believe > boost::variant presently attempts to do that. You can always try! > Or, maybe can’t [image: Winking smile]) (I really have a user’s > knowledge/attitude to variant). > I meant, literally, you can just try it: boost::variant< int, int > x(0); [...] > >> Hmmm...then why are you using variant? > Because I need a single type as an output from my various templates. > Say you are solving a PDE. And your various PDE classes contain > (coefficient) functions of all kinds ( contstants, zeros etc.) Then I want > to have a unique type > as an output. A variant seemed like a good idea. The type of the function > is known at compile time. I just don’t want to carry around O(N^2) types > where N the dimensionality of the PDE > - and this is just for the cross terms. > Hmmm...okay; have you consider boost::function? > >>Well, variant essentially erases the type of the object it's constructed > with, so you're effectively using runtime polymorphism (though of a more > controlled nature than boost::any or virtual functions). I don't know > enough > about the particulars of your application based on your description above > to know if that's appropriate. > Here is a problem to understand what I am thinking of (only for info > purposes, no purpose of cluttering you): > Say, I have a vector Monte-Carlo engine that advances like > V(t_dt) = m*dt * sigma*Fi*zeta*random > where now m, sigma, Fi, zeta can be zero or one and have various classes > that produce them. I want to have a single class for the advancement > (actually there are various different classes dependent on the numerical > method). > Now, I can use expression templates for them, but there are significant > gains if I know that certain type are fixed (say, m = 0 and/or zeta = 1 ). > This is why I want to ba able to have these functions in a controlled > manner (they are only a few of those, so a variant seems natutral. > The same with a PDE example. > It sounds like the optimizations you're looking for are pretty application specific. For example, if you perform runtime checks on whether some of your factors are constant or zero to avoid recomputing some factors or avoid computing other factors altogether, you *might* get some performance gains in some situations but you'll probably lose performance in other situations. It depends on whether the branching for those checks hurts you, what the relative cost is of computing the more expensive factors, etc. I might suggest delaying the type erasure as much as possible. For example, set up your interface such that you package the entire expression m * dt * sigma * Fi * zeta * random into a type-erased object (like boost::function) and use the static types for the individual factors. I don't know if that's possible or reasonable for your use case but it might give you some ideas. What I really need is some variant type that encapsulates what I described > above. The number of calls to the subscript operator is going to be in the > millions. (btw this is what I call opimized) > Every call to the subscript operator is going to have to dispatch through the which() index to determine the underlying dynamic type of the variant. This is likely going to be significantly slower than indexing a std::vector. The only way to be sure is to benchmark it yourself. [...] > PS: No offense to anyone, but the documentation is a bit obscure. I think > there would be a certain benefit, if in the documentation there was some > info on implementation issues, to allow people > to make more educated decisions. > That's fair; it's likely like that since the implementation is liable to change, or vary greatly across various compilers depending on which compilers perform best with which implementation. Ultimately, if you're to the point where you need to know the implementation of boost::variant for something, you'd probably have to look at the source code anyway to be sure. > Maybe it is my fault, but after having spent some time with it, I still do > not know what is contained in the data structure ( copies, > references/pointers-to-external objects, who knows), > A boost::variant just "holds" an object of one of its value types. It's the same idea as a union, e.g., a boost::variant< int, double > is basically the same as struct V { union { int i; double d; } u; int which; }; Or maybe instead of an index to discriminate what's in the union, a pointer is used; that's implementation-dependent. what are the guarantees of compile-time variant etc. > Actually the guarantees of boost::variant are very well documented and (I thought) a strong point of the documentation... - Jeff
Hi Jeff, Thank you for your careful response. I am now increasingly convinced that boost::variant was the wrong choice for my problem at hand. Dispatching to “which()” with every call is unacceptable performance-wise. I am not familiar with boost::function, started looking into it last night. O/wise, I can always typedef inside each generator class the outcome to, say, result_type and then have an algebra on the result_type-s. Thank you very much for all your help and time, Petros From: Jeffrey Lee Hellrung, Jr. Sent: Wednesday, July 11, 2012 8:23 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] compilation problem and a coupleofboost::variantquestions On Wed, Jul 11, 2012 at 4:38 PM, Petroswrote: [...] >> You mean the first type in the sequence of value types that is convertible from the argument? That's possible, but I don't believe boost::variant presently attempts to do that. You can always try! Or, maybe can’t ) (I really have a user’s knowledge/attitude to variant). I meant, literally, you can just try it: boost::variant< int, int > x(0); [...] >> Hmmm...then why are you using variant? Because I need a single type as an output from my various templates. Say you are solving a PDE. And your various PDE classes contain (coefficient) functions of all kinds ( contstants, zeros etc.) Then I want to have a unique type as an output. A variant seemed like a good idea. The type of the function is known at compile time. I just don’t want to carry around O(N^2) types where N the dimensionality of the PDE - and this is just for the cross terms. Hmmm...okay; have you consider boost::function? >>Well, variant essentially erases the type of the object it's constructed with, so you're effectively using runtime polymorphism (though of a more controlled nature than boost::any or virtual functions). I don't know enough about the particulars of your application based on your description above to know if that's appropriate. Here is a problem to understand what I am thinking of (only for info purposes, no purpose of cluttering you): Say, I have a vector Monte-Carlo engine that advances like V(t_dt) = m*dt * sigma*Fi*zeta*random where now m, sigma, Fi, zeta can be zero or one and have various classes that produce them. I want to have a single class for the advancement (actually there are various different classes dependent on the numerical method). Now, I can use expression templates for them, but there are significant gains if I know that certain type are fixed (say, m = 0 and/or zeta = 1 ). This is why I want to ba able to have these functions in a controlled manner (they are only a few of those, so a variant seems natutral. The same with a PDE example. It sounds like the optimizations you're looking for are pretty application specific. For example, if you perform runtime checks on whether some of your factors are constant or zero to avoid recomputing some factors or avoid computing other factors altogether, you *might* get some performance gains in some situations but you'll probably lose performance in other situations. It depends on whether the branching for those checks hurts you, what the relative cost is of computing the more expensive factors, etc. I might suggest delaying the type erasure as much as possible. For example, set up your interface such that you package the entire expression m * dt * sigma * Fi * zeta * random into a type-erased object (like boost::function) and use the static types for the individual factors. I don't know if that's possible or reasonable for your use case but it might give you some ideas. What I really need is some variant type that encapsulates what I described above. The number of calls to the subscript operator is going to be in the millions. (btw this is what I call opimized) Every call to the subscript operator is going to have to dispatch through the which() index to determine the underlying dynamic type of the variant. This is likely going to be significantly slower than indexing a std::vector. The only way to be sure is to benchmark it yourself. [...] PS: No offense to anyone, but the documentation is a bit obscure. I think there would be a certain benefit, if in the documentation there was some info on implementation issues, to allow people to make more educated decisions. That's fair; it's likely like that since the implementation is liable to change, or vary greatly across various compilers depending on which compilers perform best with which implementation. Ultimately, if you're to the point where you need to know the implementation of boost::variant for something, you'd probably have to look at the source code anyway to be sure. Maybe it is my fault, but after having spent some time with it, I still do not know what is contained in the data structure ( copies, references/pointers-to-external objects, who knows), A boost::variant just "holds" an object of one of its value types. It's the same idea as a union, e.g., a boost::variant< int, double > is basically the same as struct V { union { int i; double d; } u; int which; }; Or maybe instead of an index to discriminate what's in the union, a pointer is used; that's implementation-dependent. what are the guarantees of compile-time variant etc. Actually the guarantees of boost::variant are very well documented and (I thought) a strong point of the documentation... - Jeff -------------------------------------------------------------------------------- _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Hi Jerry,
I did contain the variant of the Variant<_V,_Z,_U> and, after a few changes, it managed to compile !!!
Thank you for all the help,
Petros
From: Jeffrey Lee Hellrung, Jr.
Sent: Wednesday, July 11, 2012 4:10 PM
To: boost-users@lists.boost.org
Subject: Re: [Boost-users] compilation problem and a couple ofboost::variant questions
On Wed, Jul 11, 2012 at 11:32 AM, Petros
participants (3)
-
Jeffrey Lee Hellrung, Jr.
-
Larry Evans
-
Petros