I'm using inheritance with a set of classes. One of the child classes takes in an std::function(ReturnTy<ParamTypes...>)
, along with the ParamTypes
arguments. The class signature and constructor look like:
template<class ReturnTy, class... ParamTypes>
class Child : public Interface
{
public:
Child(ReturnTy default_value, ParamTypes... args)
: func_set_(false)
, m_Args(std::make_tuple(std::forward<ParamTypes>(args)...))
, m_ReturnValue(default_value)
{}
private:
bool func_set_;
std::function<ReturnTy(ParamTypes...)> m_Funciton;
std::tuple<ParamTypes...> m_Args;
ReturnTy m_ReturnValue;
};
My issue is when I want to specialize for the case where there are no parameters. Furthermore, I also want to specialize for the case which ReturnTy=void
and there are parameters. I found an answer that is close to what I'm looking for here, but it doesn't exactly cover what I'm trying to do because that question uses compile-time integers as template parameters, where I'm using types. It also concerns functions instead of classes. I feel like I'm close, but I just need some help to make my code work.
For reference, here is what I have for the other specializations (shortened):
template<class ReturnTy>
class Child<ReturnTy> : public Interface
{
public:
Child(ReturnTy default_value)
: // The same as first class without m_Args
{}
private:
// Same as first class without m_Args
};
template<class... ParamTypes>
class Child<void, ParamTypes...> : public Interface
{
public:
Child(ParamTypes... args)
: // Same as first class without m_ReturnValue
private:
// Same as first class without m_ReturnValue
};
Edit
Specifically, the issue comes from something like the following line of code:
Child<void> obj1(5);
The problem is that your specializations are of the same level (no one is more specialized that the other) and Child<void>
matches both.
If you want that Child<void>
matches the Child<ReturnTy>
case (otherwise the solution is simple and elegant: in the second specialization, split the ParamTypes...
list in a Par0
mandatory type and the rest of the ParamTypes...
) I don't see a simple and elegant solution.
The best I can imagine, at the moment, is add a level of indirection (add a Child_base
class) adding also a template parameter to explicit the desired solution.
Maybe can be made in a simpler way (sorry but, in this moment, I can try with a compiler) but I imagine something as follows
template <typename RT, bool, typename ... PTs>
class Child_base : public Interface
{
// general case (no empy PTs... list and no void return type)
};
template <typename ... PTs>
class Child_base<void, true, PTs...> : public Interface
{
// case return type is void (also empy PTs... list)
};
template <typename RT>
class Child_base<RT, false> : public Interface
{
// case return type only, but not void, and empy PTs
};
template <typename RT, typename ... PTs>
class Child
: public Child_base<RT, std::is_same_v<void, RT>, PTs...>
{
};
This way, Child<void>
inherit from Child_base<void, true>
that matches the first specialization of Child_base
but doesn't match the second one.
I propose another way about Child
: instead of define it as a class derived from Child_base
, you can try defining it as a using
alias of Child_base
template <typename RT, typename ... PTs>
using Child = Child_base<RT, std::is_same_v<void, RT>, PTs...>;
Maybe renaming Child_base
with a more appropriate name.