Generic Name
Generic Name

Reputation: 1270

C++ Cascading type conversion

How do I get type conversion to work when cascading the type conversions?

The following code should be simple, but converison from TypeB to int requires the compiler to deduce two type conversions automatically. But it does not.

I can not simply implement operator int() const { return val; } on the TypeB class because this is supposed to be a template class And I can not know which type to convert to.

class TypeA {
public:
   TypeA( int a ) : val( a ) {}
   operator int () const { return val; }
private:
   int val;
};

class TypeB {
public:
   TypeB( TypeA a ) : val( a ) {}
   operator TypeA () const { return val; }
   // operator int() const { return val; }  // Explicit conversion to int which I can not know.
private:
   TypeA val;
};

void main() {
   TypeA a = 9;
   TypeB b = a;
   int int_a = a;
   TypeA a2 = b;
   int int_b = b;    // Compilation error: 
                     // No suitable conversion function from 'TypeB' to 'int' exists
}

Regards

Upvotes: 1

Views: 574

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275270

So you want TypeB<T> to use the user defined conversions of T?

Create a template operator U that uses SFINAE to examine the conversion operators of T and accept when U is a type T has an operator U for.

An insufficient, yet easy, way is std::is_convertible -- address of T::operator U is probably better.

This will require C++11 features to do reasonably, because you'll want to use enable_if in a default template parameter.

This is a sketchy implementation: I don't cover the target type having a constructor that takes the source type.

#include <utility>
#include <type_traits>
#include <iostream>

struct A {
  operator int() { return 7; }
};

template<typename T>
struct unevaluated: std::true_type {};

template<typename T, typename U, typename=void>
struct has_user_defined_conversion:std::false_type {};

template<typename T, typename U>
struct has_user_defined_conversion<T, U,
  typename std::enable_if< unevaluated<
    decltype(
      &T::operator U
    )
  >::value >::type
>: std::true_type {};

template<typename T>
struct fake {
  T t;
  template<typename U,
    typename=typename std::enable_if<has_user_defined_conversion<T,U>::value>::type
  >
  operator U() { return t; }
};

int main() {
  int x = fake<A>();
  std::cout << x << "\n";
}

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 476950

In any implicit conversion sequence you are allowed at most one implicit user-defined conversion.

You can say int int_b = static_cast<TypeA>(b);, though, to bring the number of UDCs down to one.

Upvotes: 3

Related Questions