Boost logo

Boost :

From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2008-05-08 12:58:47


>> template <>
>> geometry_traits<UserPolygonSet> {
>>
>> typedef polygon_set_concept geometry_concept;
>> typedef UserPolygonSet operator_arg;
>> };
>>
>> ...
>>
>> template <typename geometry_type_1, typename geometry_type_2>
>> polygon_set_view operator&(
>> typename geometry_traits<geometry_type_1>::operator_arg const&
geo1,
>> typename geometry_traits<geometry_type_2>::operator_arg const&
geo2);
>>
Giovanni wrote:
>This can't work: geometry_type_{1,2} are in a non deducible context.
>You need to SFINAE on an
>is_polygon_set trait. It can still break if the user class happens to
>have an operator& with different
>behaviour. I think you'll have an hard time using operators on user
>classes without explicitly stating
>that those operators are concept requirements, i.e. the user has to
>explicitly define them for their classes.
>Of course your library may provide shortcuts help define them more
easily.

Oh yes, of course. How about this, keep the registration with
geometry_traits, but put the use of it on the return type:

template < typename geometry_type_1, typename geometry_type_2>
polygon_set_view<typename
geometry_traits<geometry_type_1>::operator_arg>,
                typename geometry_traits<geometry_type_2>::operator_arg,
op_and>
operator&(geometry_type_1 const& geo1, geometry_type_2 const& geo2);

Since the polygon_set_view needs to be templated in terms of the
arguments anyway, the indirection provides the opportunity for SFINAE to
prevent conflicts with operators for types that haven't been registered
for use with the gtl operators. See correctly compiling code example
below for full details.

If the user has an operator & with different behavior that does cause
them a problem I would expect them to not provide the trait that allows
the type to be used with operator syntax. That type would result in
substitution failure. I also can't use the operators internally in any
circumstance where the arguments may be user types since I can't rely on
them being registered. I don't want to require the user to define the
operators because that would lead to too much code to adapt the library
to their type system. It also leaves users who have already defined the
operator for a different purpose unable to use the library with that
type at all, whereas there would be an alternative syntax for types that
can't be used with the operators.

Thanks for pointing out my error,
Luke

#include <iostream>
template <typename T>
struct A { };

struct B {};
struct C {};
struct D {};

template<>
struct A<B> { typedef B operator_arg; };
template<>
struct A<C> { typedef C operator_arg; };

template <typename T1, typename T2>
struct operator_result {
        const T1& t1; const T2& t2;
        operator_result(const T1& t1_in, const T2& t2_in): t1(t1_in),
t2(t2_in) {}
        void print() {std::cout << "hello world\n"; }
};

template <typename T1, typename T2>
operator_result<typename A<T1>::operator_arg,
                typename A<T2>::operator_arg>
operator&(const T1& lvalue, const T2& rvalue) {
        return operator_result<typename A<T1>::operator_arg,
                typename A<T2>::operator_arg>(lvalue, rvalue);
}

int main() {
        B b;
        C c;
        (b & c).print();
        D d;
        //the next line does not compile
        //because D is not registered with A
        //(d & b).print();
        return 0;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk