Reputation: 2044
I want to create a pure virtual interface for every type in a variadic template. For example, a class:
overloads_interface<int,float,bool>
That defines the functions:
virtual void overload(const int& arg) = 0
virtual void overload(const float& arg) = 0
virtual void overload(const bool& arg) = 0
And if I add another type to the varaidic template, e.g
overloads_interface<int,float,bool, std::string>
It will automatically add the overload:
virtual void overload(const std::string& arg) = 0
Then, in order to instantiate this class, I must implement the functions, e.g:
class concrete : public overloads_interface<int,float,bool> {
public:
virtual void overload(const int& arg) override { /**handle int**/ }
virtual void overload(const float& arg) override { /**handle float**/ }
virtual void overload(const bool& arg) override { /**handle bool**/ }
};
Here is my best attempt of creating this class:
template<typename... args>
class overloads_interface {
using param_pack = std::tuple<args...>;
static constexpr size_t num_args = sizeof... (args);
template<size_t i = num_args - 1>
struct crtp : public crtp<i - 1> {
using arg = typename std::tuple_element<i, param_pack>::type;
using super = crtp<i - 1>;
using super::overload; // unhide overload from super class
virtual void overload(const arg& arg) = 0;
};
template<>
struct crtp<0> {
using arg = typename std::tuple_element<0, param_pack>::type;
virtual void overload(const arg& arg) = 0;
};
};
But this fails to compile:
/main.cpp:21: error: explicit specialization in non-namespace scope ‘class overloads_interface<args>’
template<>
^
/main.cpp:22: error: template parameters not deducible in partial specialization:
struct crtp<0> {
^~~~~~~
And also has a nested class crtp
that I don't really want.
How could I make this class?
Upvotes: 2
Views: 158
Reputation: 468
Another way:
template <class T>
struct overloads_helper{
virtual ~overloads_helper() = default;
virtual void overload(const T&) = 0;
};
template <class... Args>
class overloads : public overloads_helper<Args>...{
};
Not sure which one is better, inheritance chain or multiple inheritance from interfaces...
Upvotes: 9
Reputation: 63144
I'm not sure why you're bothering with std::tuple
at all, you can simply use partial specialization to unwind the pack:
template<typename... args>
struct overloads;
template<typename head, typename... args>
struct overloads<head, args...> : overloads<args...> {
using overloads<args...>::overload; // unhide overload from super class
virtual void overload(const head& arg) = 0;
};
template <typename head>
struct overloads<head> {
virtual void overload(const head& arg) = 0;
};
Also note that your crtp
is not actually a CRTP, that pattern is about classes of the form class A : Crtp<A> { };
.
Upvotes: 5