I am trying to figure out how to resolve an ambiguity problem with function names in base classes.
#include <type_traits>
template <typename T, typename PARENT>
class BaseA
{
public:
BaseA(PARENT& p) : _parent(p) {}
public:
template <typename P_ = PARENT>
auto& parent() {
if constexpr (std::is_same_v<P_, PARENT>) {
return _parent;
} else {
return _parent.template parent<P_>();
}
}
private:
PARENT& _parent;
};
class AbstractBaseB {
};
class BaseB : public AbstractBaseB
{
public:
AbstractBaseB* parent() { return _parent; }
private:
AbstractBaseB* _parent;
};
class Z {
public:
void foo() {}
};
class Y : public BaseA<Y, Z>, public BaseB
{
public:
Y(Z& z) : BaseA(z) {
}
void foo() {}
};
class X : public BaseA<X, Y>, public BaseB
{
public:
X(Y& y) : BaseA(y) {
//This will compile
BaseA::parent().foo();
//This will NOT compile
BaseA::parent<Z>().foo();
}
};
int main()
{
Z z;
Y y(z);
X x(y);
}
This is a very specific/odd use case, so I have a working example here:
https://cppinsights.io/s/08afbad9
To get it to compile, just comment out line 58. With 58 enabled, this is where I get the ambiguity which is due to line 16:
return _parent.template parent<P_>();
Since _parent is of a different type than this instance of the BaseA template, I can't just do:
return _parent.template BaseA::parent<P_>();
like I did on line 57.
How do I go about fixing this?
For those who ask, the purpose of the templated parent method is to get the "Nth" nested parent without having to do something like parent().parent().parent()
If you want member function (templates) of the same name to be considered from multiple base classes you need to explicitly import them into the derived class scope:
class Y : public BaseA<Y, Z>, public BaseB
{
public:
/*...*/
using BaseA::parent;
using BaseB::parent;
};
Related
I've got a class Base from which I have two classes, DerivedA and DerivedB as defined below.
template <typename Derived>
class Base{
public:
double interface(){
static_cast<Derived*>(this)->implementation();
}
};
class DerivedA : public Base<DerivedA>{
public:
double implementation(){ return 2.0;}
};
class DerivedB : public Base<DerivedB>{
public:
double implementation(){ return 1.0;}
};
In short, I'm trying to do the following to maintain a collection of objects, some of which are DerivedA and some of which are DerivedB:
std::vector<std::shared_ptr<Derived>>
Which is obviously impossible beacuse I've now made the class Derived a templated class.
Is there any way I can create / maintain a polymorphic collection of objects?
EDIT: Unfortunately, a simple templated structure does not work as the function implementation is templated in my actual program -- so then implementation would have to be a templated pure virtual function, which cannot be. Pardon my lack of explanation.
This answer pertains to the question as it was at the time of this answer.
Don't use CRTP, which is not dynamic polymorphism, to create dynamic polymorphism.
Use a virtual function.
That's what they're for.
class Base
{
private:
virtual
auto implementation() -> double = 0;
public:
auto interface() -> double { return implementation(); }
};
class DerivedA
: public Base
{
private:
auto implementation() -> double override { return 2.0; }
};
class DerivedB
: public Base
{
private:
auto implementation() -> double override { return 1.0; }
};
Alf's suggestion is on target. It is easy to adapt it to your additional requirement. Define an interface with a pure virtual method:
struct BaseInterface {
virtual ~BaseInterface() {}
virtual double interface() = 0;
};
Now, your template base class can derive from the interface:
template <typename Derived>
class Base : BaseInterface {
public:
double interface(){
static_cast<Derived*>(this)->implementation();
}
};
Now, you can create a vector of pointers to the interface:
std::vector<std::shared_ptr<BaseInterface>>
Because Base<DerivedA> is a completely different type compared to Base<DerivedB>, you are right that you can't just do something like std::vector<std::shared_ptr<Base>>, as it would be syntactically invalid and has no meaningful semantics with regards to C++.
One way to achieve what you want and preserve your current CRTP hierarchy is to create a type erasing interface (or is it what it should be called? I'm not sure...). It is basically a wrapper that defines a certain interface in which you could wrap objects that obey that interface.
#include <vector>
#include <memory>
#include <iostream>
class VirtualBase { // Really am not sure what it should be called, sorry
class Interface {
public:
virtual ~Interface() = default;
virtual double get() = 0;
};
template<typename T>
class Impl : public Interface {
T m_impl_obj;
public:
Impl(T impl_obj) : m_impl_obj(std::move(impl_obj)) {}
double get() override {
return m_impl_obj.get();
}
};
std::shared_ptr<Interface> m_obj;
public:
template<typename T>
VirtualBase(T obj) : m_obj(new Impl<T>(std::move(obj))) {}
double get() {
return m_obj->get();
}
};
template <typename Derived>
class Base{
public:
double get(){
return static_cast<Derived*>(this)->implementation();
}
};
class DerivedA : public Base<DerivedA>{
public:
double get(){ return 2.0;}
};
class DerivedB : public Base<DerivedB>{
public:
double get(){ return 1.0;}
};
int main() {
std::vector<VirtualBase> v;
v.emplace_back(DerivedA{});
v.emplace_back(DerivedB{});
for(auto b : v) {
std::cout << b.get() << std::endl;
}
}
Live example
This is quite incomplete, but it should work, at least in my case if I need such a design. An excellent introduction, with explanations and rationales of how and why, is Sean Parent's talk at GoingNative 2013: http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil . Really, you should see it, including all the other great presentations in GoingNative.
Edit: this is based on an assumption that OP actually needs virtual function templates. This is apparently not the case.
It is not possible to have virtual function templates.
One way to partially simulate them is the Visitor pattern. It is often used to add dynamically dispatched functionality to existing classes. The fact that this added functionality can be templatized is overlooked all too often.
A pseudocode example
class Base
{
virtual void accept (Visitor*) = 0;
}
class Derived1 : public Base
{
void accept(Visitor* v) { v->visit(this); }
}
class Derived2 : public Base
{
void accept(Visitor* v) { v->visit(this); }
}
class Visitor
{
virtual void visit (Derived1*) = 0;
virtual void visit (Derived2*) = 0;
}
template<class X, class Y>
class FooVisitor
{
X x; Y y;
FooVisitor(X x, Y y): x(x), y(y) {}
void visit (Derived1*) { x.func(y); }
void visit (Derived2*) { y.otherfunc(x); }
}
Of course all the downsides of Visitor are here as well.
I have the following situation, where I want to instantiate an object of a template type.
I want the instantiation of the template type object to depend on the "instantiator" class.
template <class T>
class Base
{
public:
Base(){}
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test()
{
return T(5);
}
};
template <class T>
class Derived : public Base<T>
{
public:
Derived() : Base<T>() {}
virtual T Test()
{
return T(5, 6);
}
};
class Test1
{
public:
Test1(int x){}
};
class Test2 : public Test1
{
public:
Test2(int x, int y) : Test1(x) {}
};
Later in my code I want to work with Base or Derived objects.
They perform operations on a template type object (obj) in function do_something().
I want to let the instantiation of obj depend on the implementation
of the Test() function.
Base should only work with objects of type Test1 or derived classes of Test1 that have the same constructor.
Derived should only work on objects that have the same constructor as Test2.
Base<Test1>(); // works
Base<Test2>(); // doesn't work, but should not work by my design and throw a compile error
Derived<Test1>(); // same
Derived<Test2>(); // should work, but doesn't,
// since Base::Test() still exists, but cannot be compiled due to wrong constructor of T
Is there a way to implement the described behavior?
Or is there a design change I can make?
You might change Base to be correct for any T:
template <class T>
class Base
{
public:
Base(){}
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test()
{
if constexpr (std::is_constructible_v<T, int>) {
return T(5);
}
throw std::runtime_error("should not be called");
}
};
but
Base<Test2>(); would compile but throw at runtime.
Seems better to split and have two derived:
template <class T>
class Base
{
public:
Base() = default;
virtual ~Base() = default;
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test() = 0;
};
template <class T>
class Derived : public Base<T>
{
public:
Derived() : Base<T>() {}
T Test() override { return T(4); }
};
template <class T>
class Derived2 : public Base<T>
{
public:
Derived() : Base<T>() {}
T Test() override { return T(5, 6); }
};
Say I've got the following (pseudo-)code:
class base{
public:
virtual void callMe() = 0;
virtual void doRender() = 0;
}
class a : public base{
public:
virtual void callMe(){/*doA*/} override;
}
class b : public base{
public:
virtual void callMe(){/*doB*/} override;
}
class myClass : public base, public a, public b{
public:
virtual void doRender(){
this->a::callMe();
this->b::callMe();
} override;
}
Would there be a way to write this differently? Something like:
class myClass : public base, public a, public b{
public:
virtual void doRender(){
this->allSupers::callMe();
} override;
}
My goal with this would be to have a base class that can be extended to have different "features", all of which have to be executed on doRender.
I know I could of course keep track of these functions by means of a function pointer list in base, in which the subclasses put their own functions when constructed, but I'd like to avoid that. Having to iterate over these functions still gives me at least three lines of code in my final doRender. (Or one long unreadable line.)
I'm open for suggestions using templates.
Depending on you actual problem at hand, you might be able to use the mixin-style. Essentially you can have each class call the next callMe at the end (or begining) of their own callMe. One benefit is that callMe does not need to be a virtual function. Here is a minimal example (online):
#include <iostream>
class base
{
public:
void callMe() {}; // Empty base case
virtual void doRender() = 0;
};
template <class super>
class a : public super
{
public:
void callMe()
{
std::cout << "doA" << '\n';
super::callMe(); // Call the next
};
};
template <class super>
class b : public super
{
public:
void callMe()
{
std::cout << "doB" << '\n';
super::callMe(); // Call the next
};
};
template <class super>
class myClass_t : public super
{
public:
void doRender()
{
super::callMe();
};
};
using myClass = myClass_t<a<b<base> > >; // Defining the order of evaluation;
int main()
{
myClass m;
m.doRender();
}
With variadic template, you may do:
template <typename ... Ts>
class myClassTs : public base, public Ts...
{
public:
virtual void doRender(){
int dummy[] = {0, (Ts::callMe(), void(), 0)...};
static_cast<void>(dummy); // Silent warning for unused variable
} override;
}
using myClass = myClassTs<a, b>;
And in C++17, it would be
template <typename ... Ts>
class myClassTs : public base, public Ts...
{
public:
virtual void doRender(){
(static_cast<void>(Ts::callMe()), ...);
} override;
}
I have base class and a bunch of derived classes (only one here for simplicity). I also have holder class with one of derived classes as a template argument. I want holder object to create an instance of derived class. Here is the code:
class base {
protected:
int value;
public:
base() : value (0) { }
base(int value) : value(value) { }
};
class derived : public base { };
template <class T>
class holder {
public:
holder(T) {}
T create(int value) {
return T(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
holder<base*> h(&derived());
derived* d = h.create(1); // error here
}
I get an error error C2440: 'initializing' : cannot convert from 'base *' to 'derived *'. I guess that's because type of variable is holder<base*>, so create method is called with base as template argument. But how do I cast it properly if I have a lot of derived classes?
UPD.
I changed holder::create method so it uses std::remove_pointer but I still get the same compile error.
T create(int value) {
return new (std::remove_pointer<T>::type)(value);
}
You can let holder holds derived type rather than base type, and use boost::any or std::any (c++ 17) to store all the holders.
#include "iostream"
#include "boost/any.hpp"
#include "vector"
class base {
protected:
int value;
public:
base() : value (0) { }
base(int value) : value(value) { }
};
class derived1 : public base {
public:
derived1(int value) : base(value) {};
};
class derived2 : public base {
public:
derived2(int value) : base(value) {};
};
template <class T>
class holder {
public:
holder() {}
T* create(int value) {
return new T(value);
}
};
int main()
{
std::vector<boost::any> list;
holder<derived1> h1;
holder<derived2> h2;
list.push_back(h1);
list.push_back(h2);
derived1* pd1 = boost::any_cast<holder<derived1>>(list[0]).create(1);
derived2* pd2 = boost::any_cast<holder<derived2>>(list[1]).create(2);
}
Probably the question title is nonsensical so let me explain what I am trying to do! I have this template class
template <class TBase>
class A : public TBase
{
public:
A() { /* some initialization */ }
};
the "inner" class can be either of these 2:
class B1
{// no constructor required
};
class B2
{
public:
B2(int& m) : m_mode(m) { }
protected:
int& m_mode;
};
Note that B2 has a reference member variable so it needs a constructor initialization list. It is easy to create an instance of A<B1> but how does one make A<B2>? I could obviously drop the reference and use a pointer, but I wonder if this puzzle has an easy solution I cannot see?
thanks
You could specialize A:
class B1
{
};
class B2
{
public:
B2 (int& m) : m_mode (m) {};
protected:
int& m_mode;
};
template <class TBase> class A;
template <> class A <B2> : public B2
{
public:
A(int& m) : B2 (m) {}
};
template <class TBase> class A : public TBase
{
public:
A() : TBase () {};
};
int main()
{
int x = 42;
A <B1> a1;
A <B2> a2 (x);
}
All sub-object must be constructible in the manner selected by your derived constructor, and all must have an accessible destructor.
Any sub-object neither explicitly constructed in the ctor-init-list nor by an in-class initializer will be default-constructed.
(Which is forbidden for references.)
Thus, your B2 needs to gain a default-ctor, or A needs to call the existing one in the described manner.
Because A is a template, specializing it B2 is an option.
Here is my C++11 approach, using variadic templates
template <typename TBase, typename... Args>
class A : public TBase
{
public:
A(Args... args): TBase(args...) { /* some initialization */ }
};
class B1
{// no constructor required
};
class B2
{
public:
B2(int& m) : m_mode(m) { }
protected:
int& m_mode;
};
int main()
{
A<B1> fooA;
int n = 10;
A<B2, int> fooB(n);
}
In many cases, depending on how complex the base classes are and how many specializations you would end up needing, I'd prefer to use a class factory:
class B1
{
};
class B2
{
public:
B2 (int& m) : m_mode (m) {};
protected:
int& m_mode;
};
class B1Factory
{
public:
B1 Make () const { return B1(); }
};
class B2Factory
{
public:
B2Factory (int& ref) : mRef (ref) {};
B2 Make () const { return B2 (mRef); }
private:
int& mRef;
};
template <class TBase> class A : public TBase
{
public:
template <typename Factory> A (const Factory& fac)
:
TBase (fac.Make())
{
}
};
int main()
{
int x = 42;
A <B1> a1 (B1Factory());
A <B2> a2 (B2Factory (x));
}
Note here there is no need to specialize A, meaning code duplication is reduced. This is good for DRY code.
No big deal, B can have two constructors:
template <class TBase>
class A : public TBase
{
public:
A() { /* some initialization */ }
A(int & ri) : TBase(ri) { /* some other initialization */ }
};
Unused members just aren't instantiated. Of course, you get a compile time error if you use the wrong ctor.