how to end-up template layers? - c++

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.

Related

simplify using base template class statement

Often in derived template classes I need to refer to the base to access members. I end up writing code like this:
template<typename A>
struct BaseClass
{
};
template<typename B>
struct Derived : public BaseClass<int>
{
using Base = BaseClass<int>;
};
This gets more verbose and harder to maintain for a large number of classes with a lot of template arguments.
Is there a cleaner way to import base symbols in this case?
I think you can do things the other way i.e. defer the base resolution to the base class instead, so that it would be automatically resolved for any new derived class without bothering of rewriting it for each one.
Something like:
template <typename A>
struct BaseClass
{
using Base = BaseClass<A>;
};
template <typename B>
struct Derived : public BaseClass<int>
{};
Live example
If Derived is not itself a template class: You can simply use BaseClass (the inherited injected-class-name):
struct Derived : public BaseClass<int>
{
void f()
{
BaseClass::f();
}
};
If it is also a template, using Base = BaseClass<int>; is probably the best way.

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 ()
{
}

Using a Class Template's Internal Types from a Specialized Class

EDIT: I didn't actually get a chance to test out any of the suggested solutions as I went on a vacation, and by the time I was back, the people responsible for the class template had made some changes that allowed me to get around the need to use types defined in the class template itself.
Thanks to everyone for their help though.
In a nutshell - and feel free to correct my wording, templates are still a bit of voodoo to me, - I need to know if I can use a (protected) struct or a #typedef defined inside a class template from my specialized class. For example:
This is the class template:
template<typename T>
class A : public C<T>
{
protected:
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
Which I need to fully specialize for T = VAL:
template<>
class A< VAL > : public C< VAL >
{
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
If I do something like this, however, the compiler complains that a_struct is undefined in my specialized class. I tried specializing and inheriting from the class template but that got... messy.
I saw some solutions, but all of them involved modifying the class template, which is something I am not able to easily do (different team).
Thoughts?
No, you can't use members of the primary template declaration in your specialization of the class template. That is because in essence a template class specialization declares a completely new class template that is applied when the template arguments match the specialization.
You have two options available though, if you want to do something like in your example:
You can specialize the template class member function. This is useful if it is indeed only one member function that is special (or at least the number of member functions is limited).
You can bring the declaration of the member (-type) in a common base class.
Since you indicated in an edit that you can't change the class template itself, specializing the member function seems the best option.
A simplified example of specializing a member function only
template< class T>
class Printer
{
public:
struct Guard {};
void DoPrint( const T& val)
{
Guard g;
(void)g;
std::cout << val << '\n';
}
};
struct Duck {};
template<>
void Printer<Duck>::DoPrint( const Duck& val)
{
Guard g;
(void)g;
std::cout << "Some duck\n";
}
The Guard here is only used to demonstrate that this type is available to both the primary and the specialized implementation of DoPrint().
It's not beautiful, but you can do it like this:
template<typename T>
class C
{
};
template<typename T>
class A : public C<T>
{
protected:
friend A<int>;
// ^^^^^^
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
template<>
class A< int > : public C< int >
{
using a_struct = typename A<void>::a_struct;
// ^^^^^^
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
or how about, re-declaring struct a_struct in the specialized template, with same functionality as default one.
I know it may not sound good since you need to inject in all specialized templates. But that is one i can think of now.

Templated data types with derived classes

Let's say I have the following:
class Base
{
protected:
Base() { }
};
class A : public Base
{
};
class B : public Base
{
};
Now suppose I do this with a template:
TemplatedClass<Base> *generic = new TemplatedClass<A>();
It doesn't work, and I believe I understand why, but I'd like to know if I can do something equivalent. I have several template specializations of the form
typedef TemplatedClass<A> ASpec;
typedef TemplatedClass<B> BSpec;
typedef TemplatedClass<C> CSpec;
I have a single variable whose type I'd like to defer until runtime, so that I can dynamically assign it like
if(condition1)
generic = new ASpec();
else if(condition2)
generic = new BSpec();
Is there any way to go about this? I don't have the ability to change the fact that the classes are templated and not inheriting from a base class, or I'd just do that.
This is not possible in C++.
The fact that A derives from Base doesn't mean that TemplatedClass<A> derives from TemplatedClass<Base>.
See this Stack Overflow post for alternatives:
Conversion from STL vector of subclass to vector of base class
You can derive TemplatedClass<T> from TemplatedClass<Base>, either by specialising if for Base, or by providing a dummy class like this:
struct Dummy {};
template <typename T>
struct BaseClass<T> {
typedef TemplatedClass<Base> Type;
};
template <>
struct BaseClass<Base> {
typedef Dummy Type;
};
template <typename T>
struct TemplatedClass : BaseClass<T>::Type
{
//...
};

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...