What I want to do:
Create an 'InstructionSet' object that
- is held generically (without having to specify types) by a container (of pointers) elsewhere
- holds a variable number of instruction objects (with possible duplicate types) with type satisfying concept 'is_instruction_type'
- has 'extract' function that produces a new 'InstructionSet' that contains all instructions of a single particular type
I have tried to implement this by using inheritance on a variadic class such that recursion could be used to store each instruction of correct type; a pointer to type 'InstructionSet<>' can then have a virtual function used on it to be able to access the bottom of the inheritance, and recur over the object.
//Define recursively
template<typename...Args> requires (is_instruction_type<Args> && ...)
class InstructionSet;
//Base
template<>
class InstructionSet<>
{
public:
InstructionSet() {};
virtual ~InstructionSet() {};
template<typename U>
auto extract()
{
return extractHelper()->extract();
};
protected:
virtual InstructionSet<>* extractHelper();
};
//Recur
template<typename T, typename ...Rest> requires is_instruction_type<T>
class InstructionSet<T, Rest...> : public InstructionSet<Rest...>
{
public:
InstructionSet(T&& t, Rest&&...rest);
InstructionSet(T&& t, InstructionSet<Rest...>&& set);
virtual ~InstructionSet() {};
template<typename U> requires std::same_as<T, U>
auto extract();
template<typename U> requires !std::same_as<T, U>
auto extract();
virtual InstructionSet<T, Rest...>* extractHelper()
{
return this;
};
private:
T _instruction;
};
template<typename T, typename ...Rest> requires is_instruction_type<T>
inline InstructionSet<T, Rest...>::InstructionSet(T&& t, Rest&& ...rest) : InstructionSet<Rest...>(std::forward<Rest>(rest)...),
_instruction(std::forward<T>(t))
{
}
template<typename T, typename ...Rest> requires is_instruction_type<T>
inline InstructionSet<T, Rest...>::InstructionSet(T&& t, InstructionSet<Rest...>&& set)
{
_instruction = std::forward<T>(t);
std::construct_at((InstructionSet<Rest...>*)this, std::move(set));
}
template<typename T, typename ...Rest> requires is_instruction_type<T>
template<typename U> requires std::same_as<T, U>
auto InstructionSet<T, Rest...>::extract<U>()
{
return InstructionSet(_instruction, std::move(((InstructionSet<Rest...>*)this)->extract()));
}
template<typename T, typename ...Rest> requires is_instruction_type<T>
template<typename U> requires (!std::same_as<T, U>)
auto InstructionSet<T, Rest...>::extract<U>()
{
return ((InstructionSet<Rest...>*)this)->extract();
}
The two questions that I have:
- How should 'extract' be defined outside of the class under multiple templates?
- How should class members be treated inside the partially specialized class definition? (should a full class definition also come into it?)
I have tried different combinations of angle brackets being included/excluded as well as trying to move the function definitions to inside the class, but all throw errors.
I think that I understand the basics of SFINAE for classes with type definitions and static variables, however I am confused about, and cannot seem to find many examples, for more complex classes.
I think you could simplify it by not making specializations and by using a
std::tuplefor storing the instructions instead.First a helper function to create a
std::index_sequencewith all the indices in a parameter pack where the type isT:Then if you store the instructions in a
std::tuple, extraction could look like this:Demo