Reputation: 641
I define a template class in which, I define two type-cast operator
template <class base_t>
struct subclass {
base_t base;
//any function which defined for 'base_t' can be used with 'subclass<base_t>'
operator base_t&() {
return base;
}
//I want 'subclass<base_t>' can be converted to any class which 'base_t' can
//I want this operator is called only if 'target_t' is not 'base_t'
template <class target_t>
operator target_t&() {
return (target_t)base;
}
};
The class looks fine, but there're a problem when I try to convert subclass<int>
to int
. For instance:
typedef subclass<int> foo_t;
foo_t foo = {1234};
cout << foo << endl; //Error here: ambiguous; This line is compiled only if I delete 'template<class target_t> operator target_t&()'
Please tell me how
EDIT
Everything work fine if I don't define the template. However, if I define a subclass< subclass<int> >
, I can convert it to subclass<int>
but I can't convert it to int
typedef subclass<int> level1;
typedef subclass<level1> level2;
level1 a = {1234};
level2 b = {a};
cout << a << endl;
cout << b << endl; //Error! Because the compiler doesn't provide a type-cast from level2 to int
Upvotes: 1
Views: 112
Reputation: 302757
What you're trying to do makes little sense.
We have subclass<int>
. It is convertible to int&
, but also to a lot of other reference types. char&
. bool&
. double&
. The ambiguity arises from the fact that all the various overloads for operator<<
that take any non-template argument are viable overload candidates with equivalent conversion sequences. And for good measure, you probably don't want to do any of those conversions anyway.
What you want is just the base&
operator
:
template <class base_t>
struct subclass {
base_t base;
operator base_t&();
};
That's really all you need. This gives you the reference implicitly to the type you're storing, and you can already take base-class references to it too:
subclass<Derived> obj;
Base& base = obj; // totally OK with just that one operator
I don't see what problem the template operator T&
solves.
However, when I define,
subclass < subclass<int> >
and it can converted tosubclass<int>
but can't be converted toint
First of all, subclass<subclass<int>>
can be converted to subclass<int>&
, not subclass<int>
. That said, if we want that to work, we can add a conversion operator specifically for that case. First, add a type trait to find what the most nested type is:
template <class base_t>
struct subclass;
template <typename T>
struct nested { using type = T; };
template <typename T>
struct nested<subclass<T>> : nested<T> { };
And then define a template operator
conversion for the nested case:
template <typename T,
typename = std::enable_if_t<std::is_same<T, typename nested<base_t>::type>::value>>
operator T&() {
return base;
}
We make it a template so that there isn't an ambiguous overload in the case where we're just one subclass
deep. And with that, both of these work:
subclass<subclass<subclass<int>>> s{{{4}}};
int& i = s;
subclass<int> s2{5};
int& i2 = s2;
Upvotes: 2
Reputation: 2369
You can use a bit of SFINAE techniques to make this work
template <class target_t, class = std::enable_if< !std::is_same<target_t, base_t>::value && std::is_convertible<base_t, target_t>::value> >
operator target_t&() {
return (target_t)base;
}
Not the best syntax in the world, but that's how C++ currently works until Concepts Lite are standardized
Upvotes: 1