I have the following class structure.
class Base {
protected:
template <typename Type>
Type convert(); // no implementation
public:
template <typename Type>
operator Type() {
Type t(convert<Type>());
// log conversion
return t;
}
}
};
class D1: public Base
{
protected:
template <type Type>
Type convert() {
Type t;
// Set t
return t;
}
};
template <typename Type>
class D2: public Base
{
public:
D2(Type v): value(v) {}
protected:
template <typename Type2>
Type2 convert() {
return value;
}
private:
Type value;
}
I am looking for a non-templated class that can be converted into a different type by a type conversion. I do not want to make Base a templated class, as that complicates how it is used.
I would like to force D2 to only allow Type2 and Type to be the same class. As written, if Type can be cast or converted to Type2, the code will work. I am being confused as to whether convert
should be declared virtual (the answer appears to be no) and partial nested specializations.
I would like to provide a single specialization in D2 of
template <typename Type>
template <>
Type D2<Type>::convert<Type>() { ... }
but it is clear that this is not allowed.
I also tried
template <>
template <typename Type>
Type D2<Type>::convert<Type>() { ... }
which complained that "prototype for ‘Type D2::convert() const’ does not match any in class ‘D2’
I can't remove the template on convert because it is needed by D1.
Is there a way to get this to work?
At a high level, what I need is to be able to do the following:
Base *b = new D1(/*stuff*/);
int i = *b; // calls D1::convert<int> (a)
b = new D1(/*different stuff*/);
std::string s = *b; // calls D1::convert<std::string> (b)
b = new D2<int>(/* other stuff */);
int j = *b; // calls D2<int>::convert<int> (c)
b = new D2<std::string>(/*still other args*/);
s = *b; // calls D2<std::string>::convert<std::string> (d)
// This should fail as a compile time or link time error
b = new D2<int>(/*... */);
std::string s_fail = *b; // convertable to int, not string
// tries to call D2<int>::convert<std::string>, which is either
// not implemented or has an implementation that fails to compile,
// probably by casting an int to string (e)
The desired behavior is:
(a) Call a method in D1 that returns an int
(b) Call a method in D1 that returns a string
(c) Call a method in D2<int> that returns an int
(d) Call a method in D2<string> that returns a string
(e) Fail as early as possible, ideally at compile time or link time
Is that not possible in C++? I'm happy to rewrite everything except the public interface of Base, D1 not being templated and D2 being templated.
EDIT: Clarify the behavior that I want