Is there a way to specify priority among user conversions?

Disclaimer: I know that using custom implicit conversions is often not recommended. However, in our project, we need these transformations for different classes of templates in order to work well with each other.

I need to prioritize user-defined conversions, for example:

struct X{}
struct Y{}

struct Z{
    operator X(){...}
    operator Y(){...}
}

void foo(X x){...}
void foo(Y y){...}

// somewhere in some template client code
...{
    Z z = ...;
    ...
    foo(z); // WILL NOT COMPILE
}

This will not compile because converting from Zto Xor is Yambiguous. Is there any way to resolve this ambiguity. Ie, can I somehow tell the compiler: if there is a function overloaded for Xand Ythen prefer to discard Zin Xinstead of not compiling.

, . , , , , . . , - , Z foo.

+4
3

- " " :

struct P2 {};
struct P1: P2 {};

template<class A> 
void foo(A x, P1, typename std::common_type<X,A>::type* =nullptr) 
{ foo(static_cast<X>(x)); }

template<class A> 
void foo(A y, P2, typename std::common_type<Y,A>::type* =nullptr) 
{ foo(static_cast<Y>(y)); }

template<class A> void foo(A a) { foo(a,P1()); }

P2 P1 , P1, common_type , . , (SFINAE), . ... A - X Y, foo, , .

, ""

template<size_t N> struct P: P<N+1> {}
template<> struct P<10> {}

SFINAE P<1>, P<2> .. P<10> P<0>()

+1

, smart Ts..., Ts..., , :

namespace details {
  template<class...>struct types{using type=types;};
  template<class U, class Types, class=void>
  struct smart_cast_t:std::false_type {
    using type=U;
    template<class A>
    U operator()(A&& a)const{return std::forward<A>(a);}
  };
  template<class U, class T0, class...Ts>
  struct smart_cast_t<
    U, types<T0, Ts...>,
    typename std::enable_if<std::is_convertible<U, T0>::value>::type
  >:std::true_type
  {
    using type=T0;
    template<class A>
    T0 operator()(A&& a)const{return std::forward<A>(a);}
  };
  template<class U, class T0, class...Ts>
  struct smart_cast_t<
    U, types<T0, Ts...>,
    typename std::enable_if<!std::is_convertible<U, T0>::value>::type
  >:smart_cast_t< U, types<Ts...> >
  {};
}

template<class... Ts, class U>
auto smart_cast( U&& u )
-> decltype(details::smart_cast_t< U, details::types<Ts...> >{}( std::forward<U>(u) ))
{
  return details::smart_cast_t< U, details::types<Ts...> >{}( std::forward<U>(u) );
}

, foo :

void foo_impl(X);
void foo_impl(Y);

template<class A>
void foo(A&& a) {
  foo_impl( smart_cast<X, Y>(std::forward<A>(a)) );
}

foo, , A X, Y.

, foo types< types<X,Y> > foo , , .

++ 11. ++ 14 smart_cast.

. types ( ).

details::smart_cast_t , U U. U , . , , .

, - smart_cast< type1, type2, type3, etc >( expression ). U , , .

: - , .

, , . static_cast<T0> - smart_cast_t, .

smart_cast_t true_type false_type . , smart_cast_t<U, types<Ts...>>::value , U Ts..., U.

rvalue vs lvalue. , a U a U&&, r. - U - , , , smart_cast<int, double>(std::string("hello")) std::string, operator() smart_cast_t.

, smart_cast<int, double>(""). - typename std::decay<U>::type - .

+1

Yes, enter it explicitly:

foo(static_cast<Y>(z));
0
source

All Articles