
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; }