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.
Related
Is it possible to declare some type of base class with template methods which i can override in derived classes? Following example:
#include <iostream>
#include <stdexcept>
#include <string>
class Base
{
public:
template<typename T>
std::string method() { return "Base"; }
};
class Derived : public Base
{
public:
template<typename T>
std::string method() override { return "Derived"; }
};
int main()
{
Base *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
I would expect Derived as the output but it is Base. I assume it is necessary to make a templated wrapper class which receives the implementing class as the template parameter. But i want to make sure.
1) Your functions, in order to be polymorphic, should be marked with virtual
2) Templated functions are instantiated at the POI and can't be virtual (what is the signature??How many vtable entries do you reserve?). Templated functions are a compile-time mechanism, virtual functions a runtime one.
Some possible solutions involve:
Change design (recommended)
Follow another approach e.g. multimethod by Andrei Alexandrescu (http://www.icodeguru.com/CPP/ModernCppDesign/0201704315_ch11.html)
Template methods cannot be virtual. One solution is to use static polymorphism to simulate the behavior of "template virtual" methods:
#include <iostream>
#include <stdexcept>
#include <string>
template<typename D>
class Base
{
template<typename T>
std::string _method() { return "Base"; }
public:
template<typename T>
std::string method()
{
return static_cast<D&>(*this).template _method<T>();
}
};
class Derived : public Base<Derived>
{
friend class Base<Derived>;
template<typename T>
std::string _method() { return "Derived"; }
public:
//...
};
int main()
{
Base<Derived> *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
where method is the interface and _method is the implementation. To simulate a pure virtual method, _method would absent from Base.
Unfortunately, this way Base changes to Base<Derived> so you can no longer e.g. have a container of Base*.
Also note that for a const method, static_cast<D&> changes to static_cast<const D&>. Similarly, for an rvalue-reference (&&) method, it changes to static_cast<D&&>.
Another possible aproach to make your example work as you expect is to use std::function:
class Base {
public:
Base() {
virtualFunction = [] () -> string { return {"Base"}; };
}
template <class T> string do_smth() { return virtualFunction(); }
function<string()> virtualFunction;
};
class Derived : public Base {
public:
Derived() {
virtualFunction = [] () -> string { return {"Derived"}; };
}
};
int main() {
auto ptr = unique_ptr<Base>(new Derived);
cout << ptr->do_smth<bool>() << endl;
}
This outputs "Derived". I'm not sure that this is what you realy want, but I hope it will help you..
I had the same problem, but I actually came up with a working solution. The best way to show the solution is by an example:
What we want(doesn't work, since you can't have virtual templates):
class Base
{
template <class T>
virtual T func(T a, T b) {};
}
class Derived
{
template <class T>
T func(T a, T b) { return a + b; };
}
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
The solution(prints 3HelloWorld0.3):
class BaseType
{
public:
virtual BaseType* add(BaseType* b) { return {}; };
};
template <class T>
class Type : public BaseType
{
public:
Type(T t) : value(t) {};
BaseType* add(BaseType* b)
{
Type<T>* a = new Type<T>(value + ((Type<T>*)b)->value);
return a;
};
T getValue() { return value; };
private:
T value;
};
class Base
{
public:
virtual BaseType* function(BaseType* a, BaseType* b) { return {}; };
template <class T>
T func(T a, T b)
{
BaseType* argA = new Type<T>(a);
BaseType* argB = new Type<T>(b);
BaseType* value = this->function(argA, argB);
T result = ((Type<T>*)value)->getValue();
delete argA;
delete argB;
delete value;
return result;
};
};
class Derived : public Base
{
public:
BaseType* function(BaseType* a, BaseType* b)
{
return a->add(b);
};
};
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
We use the BaseType class to represent any datatype or class you would usually use in a template. The members(and possibly operators) you would use in a template are described here with the virtual tag. Note that the pointers are necessary in order to get the polymorphism to work.
Type is a template class that extends Derived. This actually represents a specific type, for example Type<int>. This class is very important, since it allows us to convert any type into the BaseType. The definition of the members we described described in BaseType are implemented here.
function is the function we want to override. Instead of using a real template we use pointers to BaseType to represent a typename. The actual template function is in the Base class defined as func. It basically just calls function and converts T to Type<T>. If we now extend from Base and override function, the new overridden function gets called for the derived class.
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_;
};
Is it possible to use SFINAE and std::enable_if to disable a single member function of a template class?
I currently have a code similar to this:
#include <type_traits>
#include <iostream>
#include <cassert>
#include <string>
class Base {
public:
virtual int f() { return 0; }
};
template<typename T>
class Derived : public Base {
private:
T getValue_() { return T(); }
public:
int f() override {
assert((std::is_same<T, int>::value));
T val = getValue_();
//return val; --> not possible if T not convertible to int
return *reinterpret_cast<int*>(&val);
}
};
template<typename T>
class MoreDerived : public Derived<T> {
public:
int f() override { return 2; }
};
int main() {
Derived<int> i;
MoreDerived<std::string> f;
std::cout << f.f() << " " << i.f() << std::endl;
}
Ideally, Derived<T>::f() should be disabled if T != int. Because f is virtual, Derived<T>::f() gets generated for any instantiation of Derived, even if it is never called.
But the code is used such that Derived<T> (with T != int) never gets created only as a base class of MoreDerived<T>.
So the hack in Derived<T>::f() is necessary to make the program compile; the reinterpret_cast line never gets executed.
You could simply specialize f for int:
template<typename T>
class Derived : public Base {
private:
T getValue_() { return T(); }
public:
int f() override {
return Base::f();
}
};
template <>
int Derived<int>::f () {
return getValue_();
}
No you can't rule out a member function with SFINAE. You could do it with specialisation of your Derived class f member function for convertible Ts to int but that would lead to unnecessary duplication of code. In C++17 however you could solve this with use of if constexpr:
template<typename T> class Derived : public Base {
T getValue_() { return T(); }
public:
int f() override {
if constexpr(std::is_convertible<T, int>::value) return getValue_();
return Base::f();
}
};
Live Demo
Is it possible to declare some type of base class with template methods which i can override in derived classes? Following example:
#include <iostream>
#include <stdexcept>
#include <string>
class Base
{
public:
template<typename T>
std::string method() { return "Base"; }
};
class Derived : public Base
{
public:
template<typename T>
std::string method() override { return "Derived"; }
};
int main()
{
Base *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
I would expect Derived as the output but it is Base. I assume it is necessary to make a templated wrapper class which receives the implementing class as the template parameter. But i want to make sure.
1) Your functions, in order to be polymorphic, should be marked with virtual
2) Templated functions are instantiated at the POI and can't be virtual (what is the signature??How many vtable entries do you reserve?). Templated functions are a compile-time mechanism, virtual functions a runtime one.
Some possible solutions involve:
Change design (recommended)
Follow another approach e.g. multimethod by Andrei Alexandrescu (http://www.icodeguru.com/CPP/ModernCppDesign/0201704315_ch11.html)
Template methods cannot be virtual. One solution is to use static polymorphism to simulate the behavior of "template virtual" methods:
#include <iostream>
#include <stdexcept>
#include <string>
template<typename D>
class Base
{
template<typename T>
std::string _method() { return "Base"; }
public:
template<typename T>
std::string method()
{
return static_cast<D&>(*this).template _method<T>();
}
};
class Derived : public Base<Derived>
{
friend class Base<Derived>;
template<typename T>
std::string _method() { return "Derived"; }
public:
//...
};
int main()
{
Base<Derived> *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
where method is the interface and _method is the implementation. To simulate a pure virtual method, _method would absent from Base.
Unfortunately, this way Base changes to Base<Derived> so you can no longer e.g. have a container of Base*.
Also note that for a const method, static_cast<D&> changes to static_cast<const D&>. Similarly, for an rvalue-reference (&&) method, it changes to static_cast<D&&>.
Another possible aproach to make your example work as you expect is to use std::function:
class Base {
public:
Base() {
virtualFunction = [] () -> string { return {"Base"}; };
}
template <class T> string do_smth() { return virtualFunction(); }
function<string()> virtualFunction;
};
class Derived : public Base {
public:
Derived() {
virtualFunction = [] () -> string { return {"Derived"}; };
}
};
int main() {
auto ptr = unique_ptr<Base>(new Derived);
cout << ptr->do_smth<bool>() << endl;
}
This outputs "Derived". I'm not sure that this is what you realy want, but I hope it will help you..
I had the same problem, but I actually came up with a working solution. The best way to show the solution is by an example:
What we want(doesn't work, since you can't have virtual templates):
class Base
{
template <class T>
virtual T func(T a, T b) {};
}
class Derived
{
template <class T>
T func(T a, T b) { return a + b; };
}
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
The solution(prints 3HelloWorld0.3):
class BaseType
{
public:
virtual BaseType* add(BaseType* b) { return {}; };
};
template <class T>
class Type : public BaseType
{
public:
Type(T t) : value(t) {};
BaseType* add(BaseType* b)
{
Type<T>* a = new Type<T>(value + ((Type<T>*)b)->value);
return a;
};
T getValue() { return value; };
private:
T value;
};
class Base
{
public:
virtual BaseType* function(BaseType* a, BaseType* b) { return {}; };
template <class T>
T func(T a, T b)
{
BaseType* argA = new Type<T>(a);
BaseType* argB = new Type<T>(b);
BaseType* value = this->function(argA, argB);
T result = ((Type<T>*)value)->getValue();
delete argA;
delete argB;
delete value;
return result;
};
};
class Derived : public Base
{
public:
BaseType* function(BaseType* a, BaseType* b)
{
return a->add(b);
};
};
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
We use the BaseType class to represent any datatype or class you would usually use in a template. The members(and possibly operators) you would use in a template are described here with the virtual tag. Note that the pointers are necessary in order to get the polymorphism to work.
Type is a template class that extends Derived. This actually represents a specific type, for example Type<int>. This class is very important, since it allows us to convert any type into the BaseType. The definition of the members we described described in BaseType are implemented here.
function is the function we want to override. Instead of using a real template we use pointers to BaseType to represent a typename. The actual template function is in the Base class defined as func. It basically just calls function and converts T to Type<T>. If we now extend from Base and override function, the new overridden function gets called for the derived class.
I've two classes:
struct A {
template <typename T>
void print(T& t){
// do sth specific for A
}
};
struct B : A {
template <typename T>
void print(T& t){
// do sth specific for B
}
};
In such case, the more general Base class with virtual functions (which A and B both inherit from) cannot be compiled, since there is no virtual for template. As I try to delegate generally all A or B objects under same "interface", does anyone has the idea to resolve such problem? Thank you in advance.
Sincerely,
Jun
You can think about using using CRTP.
template<typename Derived>
struct Base {
template <typename T>
void print(T& t){
static_cast<Derived*>(this)->print(t);
}
};
struct A : Base<A> {
// template print
};
struct B : Base<B> {
// template print
};
Example Usage:
template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
p->print(a);
}
This method will be called as,
foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double
Here is another demo code.
Using a proxy class to get B's method
class A {
public:
friend class CProxyB;
virtual CProxyB* GetCProxyB() = 0;
};
class B;
class CProxyB
{
public:
CProxyB(B* b){mb = b;}
template <typename T>
void printB(T& t)
{
mb->print(t);
}
B* mb;
};
class B:public A {
public:
virtual CProxyB* GetCProxyB(){return new CProxyB(this);};
template <typename T>
void print(T& t){
printf("OK!!!!!\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new B;
CProxyB* pb = a->GetCProxyB();
int t = 0;
pb->printB(t);
return 0;
}
Two options:
Option one: Virtualize the method where if the user does not provide an implementation, the Base class' is used.
template <typename T>
struct A {
virtual void print(T& t);
};
template <typename T>
void A::print(T& t) {
// do sth specific for A
}
template <typename T>
struct B : A {
virtual void print(T& t);
};
void B::print(T& t) {
// do sth specific for B
}
Option two: Abstract the method where if the user does not provide an implementation, the code will not compile.
template <typename T>
struct A {
virtual void print(T& t)=0;
};
template <typename T>
struct B : A {
virtual void print(T& t){
// do sth specific for B
}
};
template <typename T>
void B::print(T& t){
// do sth specific for B
}
Other than the above mentioned, if you do not make them virtual, the Derived class will Shadow the Base class method and that is most certainly not what you intended. Hence, impossible.
my question is how to use single pointer to different A or B objects.
You can do this without virtual functions per-se. But all you will really be doing is writing an implementation of a V-table and virtual functions.
If I were going to manually implement virtual functions, I would base it all on a Boost.Variant object. The variant would effectively hold the member data for each class. To call a function, you use a variant visitor functor. Each "virtual function" would have its own visitor functor, which would have different overloads of operator() for each of the possible types within the variant.
So you might have this:
typedef boost::variant<StructA, StructB, StructC> VirtualClass;
You could store any one of those objects in the variant. You would call a "virtual function" on the object like this:
VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);
The class FunctorA is your virtual function implementation. It is a visitor, defined like this:
class FunctorA : public boost::static_visitor<>
{
void operator()(StructA &arg){
//Do something for StructA
}
void operator()(StructB &arg){
//Do something for StructB
}
void operator()(StructC &arg){
//Do something for StructC
}
}
Visitors can have return values, which are returned by apply_visitor. They can take arguments, by storing the arguments as members of the visitor class. And so forth.
Best of all, if you ever change your variant type, to add new "derived classes", you will get compiler errors for any functors that don't have overloads for the new types.
But to be honest, you should just be using virtual functions.
By using CRTP(Curiously recurring template pattern), you can achieve static polymorphsim without virtual.
#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;
template<class Derived>
class Base{
public:
void print()
{
static_cast<Derived*>(this)->print();
}
};
class Derived1 : public Base<Derived1>
{
public:
void print()
{
MSG("Derived 1::print");
}
};
class Derived2 : public Base<Derived2>
{
public:
void print()
{
MSG("Derived 2::print");
}
};
template<class T>
void callme(Base<T>& p)
{
p.print();
}
int main()
{
Base<Derived1> p1;
Base<Derived2> p2;
callme(p1);
callme(p2);
system("pause");
return 0;
}
//Result :
//Derived 1::print
//Derived 2::print