Specializing Template Classes with Parameter Packs - c++

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.

issue is that Child<void> matches 2 (partial) specializations (where none are more specialized than the other):
template<class ReturnTy> class Child<ReturnTy> with [ReturnTy = void]
template<class... ParamTypes> class Child<void, ParamTypes...> with empty pack.
You so need extra specialization:
template<>
class Child<void> : public Interface
{
public:
Child() = default;
// ....
private:
std::function<void()> m_Function;
};
Demo

Related

C++ using declaration for parameter pack

I would like to define a class which inherits from a bunch of classes but which does not hide some specific methods from those classes.
Imagine the following code:
template<typename... Bases>
class SomeClass : public Bases...
{
public:
using Bases::DoSomething...;
void DoSomething(){
//this is just another overload
}
};
The problem is now if just one class does not have a member with the name DoSomething I get an error.
What I already tried was emulating an "ignore-if-not-defined-using" with a macro and SFINAE but to handle all cases this becomes very big and ugly!
Do you have any idea to solve this?
It would be really nice if I could define: "Hey using - ignore missing members".
Here I have some sample code: Godbolt
The problem with Jarod42's approach is that you change what overload resolution looks like - once you make everything a template, then everything is an exact match and you can no longer differentiate between multiple viable candidates:
struct A { void DoSomething(int); };
struct B { void DoSomething(double); };
SomeClass<A, B>().DoSomething(42); // error ambiguous
The only way to preserve overload resolution is to use inheritance.
The key there is to finish what ecatmur started. But what does HasDoSomething look like? The approach in the link only works if there is a single, non-overloaded, non-template. But we can do better. We can use the same mechanism to detect if DoSomething exists that is the one that requires the using to begin with: names from different scopes don't overload.
So, we introduce a new base class which has a DoSomething that will never be for real chosen - and we do that by making our own explicit tag type that we're the only ones that will ever construct. For lack of a better name, I'll name it after my dog, who is a Westie:
struct westie_tag { explicit westie_tag() = default; };
inline constexpr westie_tag westie{};
template <typename T> struct Fallback { void DoSomething(westie_tag, ...); };
And make it variadic for good measure, just to make it least. But doesn't really matter. Now, if we introduce a new type, like:
template <typename T> struct Hybrid : Fallback<T>, T { };
Then we can invoke DoSomething() on the hybrid precisely when T does not have a DoSomething overload - of any kind. That's:
template <typename T, typename=void>
struct HasDoSomething : std::true_type { };
template <typename T>
struct HasDoSomething<T, std::void_t<decltype(std::declval<Hybrid<T>>().DoSomething(westie))>>
: std::false_type
{ };
Note that usually in these traits, the primary is false and the specialization is true - that's reversed here. The key difference between this answer and ecatmur's is that the fallback's overload must still be invocable somehow - and use that ability to check it - it's just that it's not going to be actually invocable for any type the user will actually use.
Checking this way allows us to correctly detect that:
struct C {
void DoSomething(int);
void DoSomething(int, int);
};
does indeed satisfy HasDoSomething.
And then we use the same method that ecatmur showed:
template <typename T>
using pick_base = std::conditional_t<
HasDoSomething<T>::value,
T,
Fallback<T>>;
template<typename... Bases>
class SomeClass : public Fallback<Bases>..., public Bases...
{
public:
using pick_base<Bases>::DoSomething...;
void DoSomething();
};
And this works regardless of what all the Bases's DoSomething overloads look like, and correctly performs overload resolution in the first case I mentioned.
Demo
How about conditionally using a fallback?
Create non-callable implementations of each method:
template<class>
struct Fallback {
template<class..., class> void DoSomething();
};
Inherit from Fallback once for each base class:
class SomeClass : private Fallback<Bases>..., public Bases...
Then pull in each method conditionally either from the base class or its respective fallback:
using std::conditional_t<HasDoSomething<Bases>::value, Bases, Fallback<Bases>>::DoSomething...;
Example.
You might add wrapper which handles basic cases by forwarding instead of using:
template <typename T>
struct Wrapper : T
{
template <typename ... Ts, typename Base = T>
auto DoSomething(Ts&&... args) const
-> decltype(Base::DoSomething(std::forward<Ts>(args)...))
{
return Base::DoSomething(std::forward<Ts>(args)...);
}
template <typename ... Ts, typename Base = T>
auto DoSomething(Ts&&... args)
-> decltype(Base::DoSomething(std::forward<Ts>(args)...))
{
return Base::DoSomething(std::forward<Ts>(args)...);
}
// You might fix missing noexcept specification
// You might add missing combination volatile/reference/C-elipsis version.
// And also special template versions with non deducible template parameter...
};
template <typename... Bases>
class SomeClass : public Wrapper<Bases>...
{
public:
using Wrapper<Bases>::DoSomething...; // All wrappers have those methods,
// even if SFINAEd
void DoSomething(){ /*..*/ }
};
Demo
As Barry noted, there are other drawbacks as overload resolution has changed, making some call ambiguous...
Note: I proposed that solution as I didn't know how to create a correct traits to detect DoSomething presence in all cases (overloads are mainly the problem).
Barry solved that, so you have better alternative.
You can implement this without extra base classes so long as you’re willing to use an alias template to name your class. The trick is to separate the template arguments into two packs based on a predicate:
#include<type_traits>
template<class,class> struct cons; // not defined
template<class ...TT> struct pack; // not defined
namespace detail {
template<template<class> class,class,class,class>
struct sift;
template<template<class> class P,class ...TT,class ...FF>
struct sift<P,pack<>,pack<TT...>,pack<FF...>>
{using type=cons<pack<TT...>,pack<FF...>>;};
template<template<class> class P,class I,class ...II,
class ...TT,class ...FF>
struct sift<P,pack<I,II...>,pack<TT...>,pack<FF...>> :
sift<P,pack<II...>,
std::conditional_t<P<I>::value,pack<TT...,I>,pack<TT...>>,
std::conditional_t<P<I>::value,pack<FF...>,pack<FF...,I>>> {};
template<class,class=void> struct has_something : std::false_type {};
template<class T>
struct has_something<T,decltype(void(&T::DoSomething))> :
std::true_type {};
}
template<template<class> class P,class ...TT>
using sift_t=typename detail::sift<P,pack<TT...>,pack<>,pack<>>::type;
Then decompose the result and inherit from the individual classes:
template<class> struct C;
template<class ...MM,class ...OO> // have Method, Others
struct C<cons<pack<MM...>,pack<OO...>>> : MM...,OO... {
using MM::DoSomething...;
void DoSomething();
};
template<class T> using has_something=detail::has_something<T>;
template<class ...TT> using C_for=C<sift_t<has_something,TT...>>;
Note that the has_something here supports only non-overloaded methods (per base class) for simplicity; see Barry’s answer for the generalization of that.

Template only for smart pointer

Hi I am not sure that this is possible since but I thought of asking since there might be better ways of achieving something similar that I am not aware of.
For simplicity lets just consider that VectorT is
template<class T>
class VectorT: private std::vector<T>`
An attempt to what I wanted to have is something along the lines of.
namespace detail
{
template<class SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr>
{
public:
MyClassVectorBase() = default;
// all common functions of MyVectorView and MyVector
};
}
using MyClassVectorView = detail::MyClassVectorBase<nonstd::observer_ptr<SomeClass>>;
class MyVector : public detail::MyClassVectorBase<std::unique_ptr<SomeClass>>
{
// only functions related to the actual owner vector
};
What I am hoping is that MyClassVectorBase can be templated only on the smart pointer type and only accept SomeClass.
I thought that it might be possible with a specialization but I got no idea what the syntax for something like that would be
template<class T, class SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr<T>>
{
};
template<SomeClass T, typename SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr<T>>
{
};
Is something like that even possible ?
Edited:
Ok let me try to explain this and the logic behind it. I need to have a VectorT of Foo objects. Only Foo and nothing else.
In one case the class will be the owner of the objects and have a few extra functions.
Since it is the owner it will be class MyClassVector : public VectorT<std::unique_ptr<Foo>>
Then I have to somehow operate on these objects but these wont be owned.
The ownership is single and will always outlive the object that I will operate on so no need for shared_ptr.
So Then I guess my class will be a "View class" MyClassVectorView : public VectorT<std::observer_ptr<Foo>>
Instead of observer_ptr it could as well be say raw ptr but the intent is better with it.
Now MyClassVectorView will have all identical functions with MyClassVector which is why I think that I would be inheriting from it.
To do so I need to have a base class that will accept both unique_ptr and observer_ptr.
Then I can avoid duplication so long as I can do MyClassVector : public MyClassVectorView<std::unique_ptr<Foo>>
The alterantive would be have one class and detect with SFINAE if the template parameter is a unique_ptr and then enable the extra functions. This would avoid the extra inheritance.
Not sure about what you want to obtain but I suspect that you need template template parameters.
I suppose you could declare (but not define) MyClassVectorBase as receiving a single template typename parameter
template <typename>
class MyClassVectorBase;
and next define a specialization template-template based; something like
template <template<typename...> class SmartPtr, typename Foo>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
If Foo isn't a template parameter, but is the Foo struct, you can write
template <template<typename...> class SmartPtr>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
Your example modified and integrated (with a main() and a dummy observer_ptr)
#include <iostream>
#include <string>
#include <vector>
#include <memory>
namespace nonstd
{
template <typename T>
struct observer_ptr
{ };
}
template <class T>
class VectorT
{
public:
// expose nececssary functions
private :
std::vector<T> container_;
};
struct Foo{
double x;
};
template <typename>
class MyClassVectorBase;
// this class should only accept smart pointers of Foo
template <template<typename...> class SmartPtr, typename Foo>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
using MyClassVectorView = MyClassVectorBase<nonstd::observer_ptr<Foo>>;
class MyVector : public MyClassVectorBase<std::unique_ptr<Foo>>
{
// function only for this class but still inheriting all MyClassVectorBase stuff
};
int main ()
{
}

Template template parameters with variadic templates

For the sake of clarity, I've removed things like the constructor & destructor etc from the below where they don't add anything to the question. I have a base class that is used to create a common ancestor for a derived template class.
class PeripheralSystemBase {
public:
virtual void someFunctionThatsCommonToAllPeripherals() {}
};
template <class T, uint32_t numPeripherals = 1>
class PeripheralSystem : public PeripheralSystemBase {
public:
PeripheralSystem() : vec(T) {}
std::vector<T> vec; // different types of T is the reason why I need to template this class
};
// A & B declaration & definition are irrelevant here
class A{};
class B{};
// There are multiple different derived variants of PeripheralSystem
// At the moment, each has different template parameters
template <uint32_t customisableParam1>
class DerivedSystem1 : public PeripheralSystem<A, 1> {
public:
DerivedSystem1() : PeripheralSystem<A, 1>() {}
};
template <uint32_t customisableParam1, uint8_t customisableParam2>
class DerivedSystem2 : public PeripheralSystem<B, 1> {
public:
DerivedSystem2() : PeripheralSystem<B, 1>() {/*maybe use customisableParam2 here */}
};
So now I have 2 templates classes, each derived from the same ancestor class, one containing a vector containing type A, the other of type B; each has different template parameters. So far, so good.
Now for the question. I would like to be able to create a container template to contain none, one or more of the derived versions of PeripheralSystem inside it and I think I may be able to use variadic templates to do this, but I've got a bit stuck on the syntax over the past day or so. At compile time, I'd like to be able to create an instance of the container class. Perhaps something like:
template< template<typename ...> class args...>
class ContainerClass {
public:
ContainerClass() : container({args}) {}
std::vector<PeripheralSystem> container;
};
// possible usage
ContainerClass<DerivedSystem1<1>> cc1;
ContainerClass<DerivedSystem2<2, 3>> cc2;
ContainerClass<DerivedSystem1<1>, DerivedSystem2<2, 3>> cc3;
I know the variadic format I'm using isn't right, as I get:
error: expected ',' or '>' in template-parameter-list template<
template class args ...> >
What I'm trying to tell the compiler is that I want to supply a variable number of template-type parameters to the template, each of which has a variable number of template parameters. Am I able to do this with variadic templates please? Any suggestions on the correct syntax please?
You've got your ellipsis in the wrong place. Try:
template<template<typename...> class... Args>
^^^ here
However, you don't actually want template template parameters; since DerivedSystem1<1> is a type, not a template, you just want ordinary typename parameters:
template<typename... Args>
class ContainerClass {
For the actual container, you can't use vector<PeripheralSystem> as that is homogeneous and will slice the derived types down to PeripheralSystem. If you add a virtual destructor to PeripheralSystem you can use vector<unique_ptr<PeripheralSystem>>:
template<typename... Args>
class ContainerClass {
public:
ContainerClass() : container{std::make_unique<Args>()...} {}
std::vector<std::unique_ptr<PeripheralSystem>> container;
};
However, tuple would work just as well and result in fewer allocations:
template<typename... Args>
class ContainerClass {
public:
ContainerClass() : container{Args{}...} {}
std::tuple<Args...> container;
};

How to declare a template default value when using CRTP with several template parameters?

I want to do:
template <class Derived=BattleData>
class BattleData : public BattleCommandManager<Derived> {
};
But obviously BattleData isn't declared, so I tried a forward declaration:
template <class T> class BattleData;
template <class Derived=BattleData>
class BattleData : public BattleCommandManager<Derived> {
};
But then I get
error: "wrong number of template parameter on the second line, with
BattleData.
I really fail to see a solution to this!
Edit:
The reason I'm doing this is because I want to be able to use BattleData directly as a class, but I also want to be able to subclass it in which case I have to specify the derived class as the second template parameter.
For example let's say the corpus of my BattleData class is :
template <class Derived> class BattleData: public BaseClass<Derived> {
void foo1(){};
void foo2(){};
void foo3(){};
}
And I have a subclass
template class SubBattleData: public BattleData<SubBattleData> {
void foo1(){};
}
I would still want, in some cases, to be able to write code like this:
BattleData *x = new BattleData(...);
I can't even do the following without being able to use default arguments:
BattleData<BattleData> *x = new BattleData<BattleData>(...);
On one side, the reason functions aren't virtualized in the BattleData class is the benefit of having no virtual function. The other reason it doesn't work for me is that one of the parent CRTP classes invokes functions only if they're present in the derived type (using decltype(Derived::function) and enable-if like structures), and fall back to default behavior otherwise. Since there can be a great deal of those functions with a particular design pattern (like a CRTP that reads a protocol with many different cases and processes a case a particular way only if the derived class specify the corresponding function, otherwise just transfer it without processing).
So those functions can be present in SubBattleData and not BattleData, but both classes would work fine if instantiated, yet it's impossible to instantiate BattleData.
You should be able to accomplish your original design goals more naturally than the above. You can't use the actual Derived typename as the default clearly because what you're really trying to write is the following:
template <class Derived=BattleData <BattleData <BattleData <...>>>
class BattleData : public BattleCommandManager<Derived> {
};
You get the idea. Instead, just use a placeholder like void:
template <typename T = void>
class BattleData : public BattleCommandManager <
typename std::conditional <
std::is_same <T, void>::value,
BattleData <void>,
T
>::type>
{
};
Disclaimer: I did not compile the above.
Can't you use an Empty class for the second template parameter?
template <class T=DataContainer, class Derived=BattleData<T, Empty> >
class BattleData : public BattleCommandManager<Derived> {
};
I don't see what you are trying to do. What is wrong with
template <class T=DataContainer>
class BattleData : public BattleCommandManager< BattleData<T> > {
};
If you specify Derived to be something else than the actual derived class static polymorphism is not going to work and CRTP becomes somewhat useless anyway.
Edit: From what I have gathered this is what you want to in abstract terms:
template <class Derived>
struct Base {
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
template<typename T>
struct Derived : Base<Derived> {
// dummy so we get you example
T t;
void implementation() {
std::cout << "derived" << std::endl;
}
};
struct Derived2 : public Derived<int> {
// hide implementation in Derived
// but still have Base::interface make the right call statically
void implementation() {
std::cout << "derived2" << std::endl;
}
};
There is no way I know of that you can make this work. Another
approach would be to use policy classes instead of CRTP. They are
compatible with inheritance and you can achieve similar behaviour.
template<typename Policy>
struct BattleCmdManager : public Policy {
using Policy::foo;
};
template<typename T>
struct BattleData {
// ...
protected:
void foo();
};
struct BattleData2 : public BattleData<int {
// ...
protected:
void foo();
};
Here is how I solved it:
template <class Derived> class BattleDataInh: public BaseClass<Derived> {
void foo1(){};
void foo2(){};
void foo3(){};
};
template class SubBattleData: public BattleDataInh<SubBattleData> {
void foo1(){};
};
class BattleData : public BattleDataInh<BattleData> {
};
And that way, I can add any other template parameters too. The solution was in front of my eyes the whole time but I didn't see it...

how to end-up template layers?

When having:
template <typename Super>
class Whatever : public Super
{
...
};
is it possible, to create Whatever class without deriving from something?
Is this the lighter version?
struct BlankType{};
Whatever<BlankType> w;
////////////////////////////////////////
Some background:
I have my code composed into template layers like Whatever above. So I can do:
typedef Whatever<Whenever<Wherever<>>>> MyCombinedType
actually I can not. I have to do
typedef Whatever<Whenever<Wherever<BlankType>>>> MyCombinedType
and the type becomes also BlankType.
I can not make Wherever "non-layerable", because when I would do just
typedef Whatever<Whenever<>>> MyCombinedType
the problem will appear again...
If you want to create Whatever class that is not derived from something you can simply define its specification as follows:
class BlankType {};
template<typename T = BlankType> class Whatever : public T {};
template<> class Whatever<BlankType> {};
A bit off-topic, in C++ with variadic templates you can avoid the recursive instantiation thanks to a recursive definition:
template <class ...Bases> class Whatever;
template <class B, class ...Bases>
class Whatever<B, Bases...> : public B, public Whatever<Bases...> { /* ... */ };
template <class B>
class Whatever<B> : public B { /*... */ };
template <> class Whatever<> { /* ... */ };
Now you can say Whatever<Foo, Bar, Baz> and inherit from all those. If you want to inherit also from multiply nested other instances of Whatever, you should make all the inheritances virtual.
The final specialization in my example also shows how you can specialize Whatever to not derive from anything. If you write Whatever<> x;, you have an object of a class that does not derive from anything.