I have a number of classes that each define an inner struct Result
and are all derived from a Base
class. I'd like to have a single implementation method in the base class that returns the derived classes Result struct when called on a derived class. The below code works, but the type duplication in the actual call to get_result bothers me.
How can I make the compiler automatically deduce the template argument to the actual get_result call?
Additional restrictions:
Currently locked to c++17, but if there is a solution with newer standard versions I'd be interested to see them as well.
Edit: Some clarifications:
Base is not just there for the get_result method, it has some properties itself and is also used for polymorphism, so it cannot be completely templated.
#include <string>
using namespace std;
class Base
{
public:
// Some virtual stuff here that prevents the whole class from being templated. All derived classes need the s
template<typename T>
typename T::Result get_result() const
{
// static_assert(std::is_base_of_v<Base, T>, "Derived not derived from BaseClass");
return T::Deserialize();
}
};
class DerivedA
: public Base
{
public:
struct Result
{
int i = 0;
};
static Result Deserialize(/*In reality there is some stream argument here*/)
{
Result r;
r.i = 42;
return r;
}
};
class DerivedB
: public Base
{
public:
struct Result
{
string s;
};
static Result Deserialize(/*In reality there is some stream argument here*/)
{
Result r;
r.s = "Yatta";
return r;
}
};
int main()
{
{
DerivedA a;
const auto res = a.get_result<DerivedA>();
}
{
DerivedB b;
const auto res = b.get_result<decltype(b)>();
}
return 0;
}
Edit 2:
For now just using a free function seems to be the best solution under the circumstances:
template <class T>
typename T::Result get_result(const T& instance)
{
return T::Deserialize();
}
const auto res = get_result(a);
In C++23, you can use an explicit object to deduce the type parameter based on the static type of the object this is called on: (example)
template<typename T>
typename T::Result get_result(this const T&)
// ^^^^
{
return T::Deserialize();
}
Calling it is like a regular template with deduction:
const auto res = a.get_result();