I want to write class that extends multiple classes by (CRTP).
I can only get Extension<Base<Extension>> my_object; to work.
The api that I want is: Extension<Base> my_object;
How to make this api work?
Thanks.
Test (code is also at godbolt.org):
#include <iostream>
template <template<typename...> class Extension>
class Base1 : public Extension<Base1<Extension>> {
public:
static void beep() { std::cout << "Base1 "; }
};
template <class Plugin>
class Extension1 {
public:
Extension1() : plugin_(static_cast<Plugin*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension1\n";
}
private:
Plugin* plugin_;
};
template <template<typename...> class Plugin>
class Extension2 {
public:
Extension2() : plugin_(static_cast<Plugin<Extension2>*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension2\n";
}
private:
Plugin<Extension2>* plugin_;
};
int main() {
// This works.
Extension1<Base1<Extension1>>b;
b.beep();
// This doesn't work.
Extension2<Base1> c;
c.beep();
return 0;
}
One problem is that the template parameter to Extension2 does not match the signature that Base1 has. Another is that Extension2 does not match the parameter type expected by Base1.
If you change the definition of Extension2 to propertly accept Base1, it itself is still not a candidate to be passed to Base1. You can workaround that with an inner template class that does match what Base1 expects. This inner class would look a lot like Extension1.
template <template<template<typename...> class> class Plugin>
class Extension2 {
template <class P>
struct Inner {
Inner () : plugin_(static_cast<P *>(this)) {}
void beep() { plugin_->beep(); }
private:
P* plugin_;
};
public:
Extension2() {}
void beep() {
plugin_.beep();
std::cout << "Extension2\n";
}
private:
Inner<Plugin<Inner>> plugin_;
};
Related
I have a class that receives its base type as a template arg and I want my derived class to call a function, print. This function should use the derived implementation by default but if the base class has a print function it should use the base implementation.
#include <iostream>
class BaseWithPrint {
public:
static void print(int i) { std::cout << "Base::print\n"; }
};
class BaseWithoutPrint {
};
template <typename B>
class Derived : public B {
public:
static void print(bool b) { std::cout << "Derived::bool_print\n"; }
template <typename T>
static void print(T t) { std::cout << "Derived::print\n"; }
void Foo() {
print(1);
print(true);
print("foo");
}
};
int main()
{
Derived<BaseWithPrint> d1;
d1.Foo();
Derived<BaseWithoutPrint> d2;
d2.Foo();
return 0;
}
This code only ever calls the Derived version of print.
Code can be seen at
https://onlinegdb.com/N2IKgp0FY
If you know that the base class will have some kind of print, then you can add using B::print to your derived class. If a perfect match isn't found in the derived, then it'll check the base.
Demo
To handle it for the case where there may be a base print, I think you need to resort to SFINAE. The best SFINAE approach is really going to depend on your real world situation. Here's how I solved your example problem:
template <class T, class = void>
struct if_no_print_add_an_unusable_one : T {
// only ever called if derived calls with no args and neither
// the derived class nor the parent classes had that print.
// ie. Maybe best to force a compile fail:
void print();
};
template <class T>
struct if_no_print_add_an_unusable_one <T, decltype(T().print(int()))> : T {};
//====================================================================
template <class B>
class Derived : public if_no_print_add_an_unusable_one<B> {
using Parent = if_no_print_add_an_unusable_one<B>;
using Parent::print;
public:
// ... same as before
};
Demo
class Base { ... };
class Derived1 : Base { ... };
class Derived2 : Base { ... };
template <> class BaseDecorator<Base> : **SpecificDerived** { ... };
Is it possible for SpecificDerived to reference the particular Derived class that is being used? Such that
BaseDecorator<Derived1> bd-d1;
Would instantiate a BaseDecorator that inherits from Derived1?
The problem has come about because I need to provide a decorator for a library class and all its derivations, but want to keep the code as dry as possible.
Thanks!
If I understood your question correctly, you want your BaseDecorator to inherit from specific Derived class.
If that is the case, You may do something like this:
#include <iostream>
#include <type_traits>
class Base {
public:
virtual void f1() {
std::cout << "Base::f1" << std::endl;
}
};
class Derived1 : public Base {
public:
void f1() override {
std::cout << "Derived1::f1" << std::endl;
}
};
class Derived2 : public Base {
public:
void f1() override {
std::cout << "Derived2::f1" << std::endl;
}
};
class Derived3 {
public:
void f1() {
std::cout << "Derived3::f1" << std::endl;
}
};
template <typename T,
typename = typename std::enable_if<std::is_base_of<Base, T>::value>::type >
class BaseDecorator;
template <typename T>
class BaseDecorator<T>: public T {
public:
void f2() {
T::f1();
}
};
int main() {
BaseDecorator<Derived1> bd1;
bd1.f2();
BaseDecorator<Derived2> bd2;
bd2.f2();
//BaseDecorator<Derived3> bd3; // Compilation fails !!!
//bd3.f2(); // Compilation fails !!!
return 0;
}
Output:
Derived1::f1
Derived1::f2
Suppose we have the following sample classes:
class A {
public:
explicit A(int foo) { }
void test() {
cout << "I'm in A" << endl;
}
};
class B {
public:
explicit B(string bar) { }
void test() {
cout << "I'm in B" << endl;
}
};
I would like to define a child class to inherit from a templatized class that
could be specialized as one of either A or B. The problem I'm facing is that A
and B have different constructor arguments, so building Child's constructor is
proving to be a bit vexing. Things work if I do something like the following:
template <class ParentClass>
class Child : public ParentClass {
public:
Child<B>() : ParentClass("foo") {
}
};
int main() {
Child<B> c;
c.test();
return 0;
}
However, I'd like to also be able to do something like Child<A> c. Is this
possible?
Thanks!
You may specialize for each class:
template <class ParentClass>
class Child : public ParentClass {
public:
Child();
};
template <>
Child<A>::Child() : A(42) {}
template <>
Child<B>::Child() : B("42") {}
Demo
You can try a templated constructor as follows:
#include <iostream>
using namespace std;
class A {
public:
explicit A(int foo) { }
void test() {
cout << "I'm in A" << endl;
}
};
class B {
public:
explicit B(string bar) { }
void test() {
cout << "I'm in B" << endl;
}
};
template <class Parent>
class Child
: public Parent {
public:
template <class... Args>
Child(Args... args)
: Parent(args...) {
}
};
int main() {
Child<A> a_child(42);
Child<B> b_child("42");
a_child.test();
b_child.test();
}
You can use a delegating constructor if you want to let the user decides the parameters:
template <class ParentClass>
class Child : public ParentClass {
public:
using ParentClass::ParentClass;
};
I am implementing a template class "Holder" which should be later specialized to contain objects of different classes. The Holder stores the object is as an attribute. When storing objects which require an argument in the constructor the holder class fails on instantiation:
#include <iostream>
template<class _StoredClass>
class Holder
{
protected:
_StoredClass storedObject;
public:
void setData(_StoredClass toStore) { storedObject = toStore; }
_StoredClass getData() { return storedObject; }
};
class DummyClass
{
private:
int id;
public:
DummyClass(int myId)
{
id = myId;
}
void welcome()
{
std::cout << "This is a method of the class to which the template fits" << std::endl;
}
};
class DummyHolder : public Holder<DummyClass> {
public:
void hello()
{
std::cout << "You successfully created a class that inherited from a specialized template. Hello!" << std::endl;
}
};
int main () {
DummyClass dummyObject(1);
dummyObject.welcome();
DummyHolder dummyHolder; //error: no matching function for call to ‘DummyClass::DummyClass()’
dummyHolder.hello();
dummyHolder.setData(dummyObject);
}
How should the Holder class be implemented so that it can also store constructors with parameters but without adding new parameters to the template? Is it possible to avoid the instantiation of the attribute of the class when instantiating the class "Holder"? Actually, this object will later on be provided by the "setData" method. Therefore the instantiation is unneccesary.
I don't want to include the parameters of the constructor as another parameter of the template because that change will involve providing for each specialization this parameter, which in general is not needed.
You may create a template constructor:
template<class _StoredClass>
class Holder
{
protected:
_StoredClass storedObject;
public:
template <typename ... Ts>
Holder(Ts&&...args) : storedObject(std::forward<Ts>(args)...) {}
void setData(const _StoredClass& toStore) { storedObject = toStore; }
const _StoredClass& getData() const { return storedObject; }
};
Update DummyHolder to
class DummyHolder : public Holder<DummyClass>
{
public:
DummyHolder(int i) : Holder<DummyClass>(i) {}
void hello()
{
std::cout << "You successfully created a class that inherited from a specialized template. Hello!" << std::endl;
}
};
And in main:
DummyHolder dummyHolder(42);
Is it possible to avoid the instantiation of the attribute of the class when instantiating the class "Holder"?
You could use boost::optional:
#include <boost/optional.hpp>
template<class StoredClass>
class Holder
{
protected:
boost::optional<StoredClass> storedObject;
public:
void setData(const StoredClass& toStore) { storedObject = toStore; }
StoredClass getData() { return *storedObject; }
};
Would it be possible to disable the Foo() override in the derived class (by means of std::enable_if or some boost magic), in case T is not of a certain type, without having to write a template specialization for class Derived?
Bonus points: could the override be disabled if T does not define a certain method?
Here is my SSCCE:
#include <iostream>
#include <string>
class Base
{
public:
virtual std::string Foo()
{
return "Base";
}
};
template <typename T>
class Derived : public Base
{
public:
virtual std::string Foo() override
{
return "Derived";
}
};
int main()
{
Derived<int> testInt;
std::cout << testInt.Foo() << std::endl;
Derived<float> testFloat;
std::cout << testFloat.Foo() << std::endl;//I would like this to print 'Base'
}
UPDATE:
Thank you for the wonderful solutions, but I wasn't able to adapt them to my real code. The following example should provide a better idea of what I'm trying to achieve:
#include <iostream>
#include <string>
class Object
{
public:
void Test()
{
std::cout << "Test" << std::endl;
}
};
class EmptyObject
{
};
class Base
{
public:
virtual std::string Foo()
{
return "Base";
}
};
template <typename T>
class Derived : public Base
{
public:
virtual std::string Foo() override
{
m_object.Test();
return "Derived";
}
private:
T m_object;
};
int main()
{
Derived<Object> testObject;
std::cout << testObject.Foo() << std::endl;
Derived<EmptyObject> testEmpty;
std::cout << testEmpty.Foo() << std::endl;
}
I would do this by creating two functions that Derived::Foo can delegate to conditionally based on whether T = float. One would contain the real Derived::Foo implementation, while the other would call Base::Foo.
template <typename T>
class Derived : public Base
{
public:
virtual std::string Foo() override
{
return do_Foo(std::is_same<T, float>{});
}
private:
std::string do_Foo(std::false_type)
{
return "Derived";
}
std::string do_Foo(std::true_type)
{
return Base::Foo();
}
};
Live demo
It seems what you actually want to do is call the Derived<T>::Foo() implementation only if T defines a certain member function, otherwise Base::Foo() should be called. This can be done using expression SFINAE.
template <typename T>
class Derived : public Base
{
public:
std::string Foo() override
{
return do_Foo(true);
}
private:
template<typename U = T>
auto do_Foo(bool)
-> decltype(std::declval<U>().test(), void(), std::string())
{
return "Derived";
}
std::string do_Foo(int)
{
return Base::Foo();
}
};
Live demo
In the code above, if the type T does not define a member function named test(), the do_Foo(bool) member function template will not be viable. On the other hand, if T::test() does exist, then do_Foo(bool) will be selected because the boolean value being passed to do_Foo by Foo makes it a better match as compared to do_Foo(int).
A detailed explanation of what's going on within the decltype expression in the trailing return type can be found here.
Instead of template specialize the class, you may template specialize the method directly: (https://ideone.com/gYwt5r)
template<> std::string Derived<float>::Foo() { return Base::Foo(); }
And I only see template specialization of a class to disable future override depending of T by adding final to the virtual method.
If you need to restrict a certain type at compile time, you can use std::enable_if together with std::is_same :
typename std::enable_if<std::is_same<T, float>::value, std::string>::type
virtual Foo() override
{
return "Derived";
}
Or you can easily redirect the call to the Base method if the template type is not the type you are looking for, still with std::is_same :
virtual std::string Foo() override
{
return std::is_same<T, float>::value ? Base::Foo() : "Derived";
}
As for the Bonus, you can get the trait from this SO answer, adapted here with decltype, for a method bar() :
template <typename T>
class has_bar
{
typedef char one;
typedef long two;
template <typename C> static one test(decltype(&C::bar) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
The limitation is that you can't put constraints on the arguments or return types.
virtual std::string Foo() override
{
return has_bar<T>::value ? "Derived" : Base::Foo() ;
}
Note:
You could also use has_bar together with enable_if as in my first example, to disable it a compile time.
You can add an intermediate class to your hierarchy:
class Base
{
public:
virtual std::string Foo()
{
return "Base";
}
};
template <typename T>
class Intermediate : public Base
{
// common operations with m_object
protected: // not private!
T m_object;
};
template <typename T, typename = bool>
class Derived : public Intermediate<T> {};
template <typename T>
class Derived<T, decltype(std::declval<T>().Test(), void(), true)>
: public Intermediate<T>
{
public:
virtual std::string Foo() override
{
this->m_object.Test(); // this-> is necessary here!
return "Derived";
}
};
The full example compiles successfully with both clang 3.4 and g++ 4.8.2.