Eric, Thank you, I'll use the predicate approach for now. I like the idea of using an array base because I have a lot of existing C and C++ code which treats complex numbers as a 2 element array, and accesses the members using the [] operator. I think this is common in high-performance scientific codes. I'm afraid doing it another way could lead to the generation of a large number of conditionals which the optimizer can't figure out how to eliminate (meaning (idx ? imag() : real()), I'd have to test this on several platforms), or the introduction of a lot of casts. -Hal On Tue, 2009-10-06 at 08:56 -0400, Eric Niebler wrote:
Hal Finkel wrote:
Hello,
I'm writing a complex number class using boost::proto by extending proto::terminal< boost::array<_, 2> >. I've attached a copy of my current code, which compiles, runs, and (at least with both g++ and icc on my machine) demonstrates a significant speed improvement compared to std::complex.
However, there is (at least) one thing which don't work as it should:
In the grammar I have to specify lazy_complex< double > instead of lazy_complex< _ >, otherwise the compiler cannot find proto's operator overloads, why?
In your grammar, lazy_complex<_> is equivalent to proto::terminal< boost::array< _, 2 > >; that is, they describe the same set of expression types. Unfortunately, Proto cannot handle a grammar like that. The problem is the "2". Proto can only peer inside template instantiations as long as none of the template parameters are non-type template parameters.
There are a number of hackish solutions. You could define your own type:
template<typename T, typename Size = mpl::int_<2> > struct my_array : boost::array< T, Size::value > {};
and use my_array throughout. Then your grammar becomes proto::terminal< boost::array< _, mpl::int_<2> > >, or just proto::terminal< boost::array< _, _ > >.
The other alternative is to define a predicate that matches boost::array types:
template<typename T> struct is_boost_array : mpl::false_ {}; template<typename T, int I> struct is_boost_array<boost::array<T,I> > : mpl::true_ {};
and change your grammar to:
proto::and_< proto::terminal<_>, proto::if_<is_boost_array<proto::_value>()>
Either way. You could even just use some other terminal type besides boost::array. std::complex or std::pair would do.
Note: This code will not compile under 1.37, but will compile under 1.40, because of some issue in 1.37 which manifests itself as a problem with the overloading of the '<<' operator. I've not tested the releases in between 1.37 and 1.40.
Yes, I've fixed some bugs in this area.