I have a diamond inheritance scheme, where the last child should be able to inherit from many different parents.
A
/|\
/ | \
B C ...
| | |
* *
D E
Now imagine I have a class D : public B, class E : public B, public C, etc. From D I want to call the same function of all its parents, which I am guaranteed exists due to the inheritance. My thought was that I could wrap this in some variadic template.
Currently I have this:
template <typename T>
class A
{
public:
A(T t) : mT(t) {}
virtual ~A() {}
virtual void doThings() = 0;
protected:
T mT;
};
template <typename T, typename A = A<T>>
class B : public A
{
public:
B(T t) : A(t) {}
virtual ~B() {}
virtual void doThings() { std::cout << "B" << std::endl; }
};
template <typename T, typename A = A<T>>
class C : public A
{
public:
C(T t) : A(t) {}
virtual ~C() {}
virtual void doThings() { std::cout << "C" << std::endl; }
};
Now I thought I could do something like this, which obviously does not work:
template <typename T, typename ...Args>
class ChildGenerator : public Args...
{
public:
ChildGenerator(T t) : Args(t)... {}
// The unpacking of the variadic template does not work here.
// Do I need to make it recursive somehow? How can I do that without having to instantiate new classes B and C?
void doThings() override { Args...::doThings();}
};
My hope is that I can use it like so:
int main()
{
using B = B<double>;
using C = C<double>;
B c1(0.0);
C c2(1.0);
ChildGenerator<double, B, C> c3(2.0);
c1.doThings();
c2.doThings();
c3.doThings();
}
Expected output (order does not matter):
B
C
B // <-- order of these two does not matter
C // <--
Is what I'm trying to achieve possible?
One way to iterate over the variadic bases:
template <typename T, typename ...Args>
class ChildGenerator : public Args...
{
public:
ChildGenerator(T t) : Args(t)... {}
void doThings() override {
int dummy[] = {0, (Args::doThings(), void(), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable
}
};
or in C++17, with folding expression:
void doThings() override {
(static_cast<void>(Args::doThings()), ...);
}
Use a fold-expression (C++17):
void doThings() override { ((Args::doThings()) , ...);}
Live demo
Related
If base class is unknown to library (it is known to client), it is not so difficult to handle its constructor. The code looks like:
template<typename Parent>
struct AAAAA : public Parent
{
using Parent::Parent;
template<typename ...Args>
AAAAA(int a, int b, Args ...args) : Parent(args...) {}
};
What is the best approach, if all>1 base classes are unknown?
template<typename P1, typename P2>
struct AAAAA : public P1, public P2
{
// ...CTOR....???
};
My first thoughts are these:
A parameter pack "split" type.
2 tuples which converted to parameter packs.
For both thoughts, I don't know this time how, and if it is possible.
What comes in handy here is std::make_from_tuple.
This is how you can use a tuple for a single parent:
#include <tuple>
struct foo {
foo(int,double){}
foo(const foo&) = delete;
foo(foo&&) = default;
};
template<typename Parent>
struct A : public Parent
{
template<typename T>
A(const T& args) : Parent(std::make_from_tuple<Parent>(args)) {}
};
int main() {
A<foo> a{std::make_tuple(1,2.0)};
}
Adding a second parent should be straightforward.
Note that Parent has to be at least move-constructible to make this work.
You could require the clients to provide already constructed objects. It's easy to understand and doesn't require much typing. This requires them to be move-constructible.
#include <iostream>
#include <utility>
struct foo {
foo(int x, double y) { std::cout << x << ' ' << y << '\n'; }
};
struct bar {
bar(const std::string& x) { std::cout << x << '\n'; }
};
template<typename P1, typename P2>
struct A : public P1, public P2 {
A(P1&& p1, P2&& p2) : P1(std::move(p1)), P2(std::move(p2)) {}
};
int main() {
A<foo, bar> afb({1, 2.3}, {"hello"});
}
I have an object S. S is composed of layers S0, S1, S2 ... just like a stack of stackable drawers.
I want to create a chain of template classes A, B, C such that:
They represents proxies to different layers of the S object.
Even during template instantiation, C can convert to B, which can convert to A.
A, B, and C have different sets of methods.
The problem is that if I use public inheritance, then C will get the methods of A and B.
Test:
#include <iostream>
// Library
template <typename T>
class A {
public:
void a() {std::cout << "a\n"; }
int s_{0};
};
template <typename T>
class B : public A<T> {
public:
void b() {std::cout << "b\n"; }
};
template <typename T>
class C : public B<T> {
public:
void c() {std::cout << "c\n"; }
};
// User of library write a function like this
template <typename T>
void foo(A<T>& a) { a.a(); }
// The problem:
int main() {
C<int> c;
foo(c);
c.a(); // <--- how to hide this?
return 0;
}
I'm not sure if I understand what you want. But one way to do it is changing the access level of base class member in derived class. For example:
template <typename T>
class C : public B<T> {
public:
void c() { std::cout << "c\n"; }
private:
using A::a; // <-- reduce access level of base class member
};
"Just" need 0 + 1 + 2 + ... + i conversion operators for layer Si
Or one template conversion operator if their attributes are all the same.
But this still need some way to control the conversions.
#include <iostream>
template <typename T>
class A {
public:
A(int& layer) : layer_(layer) {}
void a() {std::cout << "a\n"; }
int s_{0};
private:
int& layer_;
};
template <typename T>
class B {
public:
B(int& layer) : a_(layer) { }
template <template<typename> class X, typename T2>
operator X<T2>() { return a_; }
void b() {std::cout << "b\n"; }
private:
A<T> a_;
};
template <typename T>
class C {
public:
C(int& layer) : b_(layer) {}
template <template<typename> class X, typename T2>
operator X<T2>() { return b_; }
void c() {std::cout << "c\n"; }
private:
B<T> b_;
};
template <typename T>
class D {
public:
D(int& layer) : c_(layer) {}
template <template<typename> class X, typename T2>
operator X<T2>() { return c_; }
void c() {std::cout << "c\n"; }
private:
C<T> c_;
};
template <template<typename> class X, typename T>
void foo(X<T>& a) {
A<T>(a).a();
}
int main() {
int v = 1;
D<int> d(v);
foo(d);
return 0;
}
I have a diamond inheritance scheme, where the last child should be able to inherit from many different parents.
A
/|\
/ | \
B C ...
| | |
* *
D E
Now imagine I have a class D : public B, class E : public B, public C, etc. From D I want to call the same function of all its parents, which I am guaranteed exists due to the inheritance. My thought was that I could wrap this in some variadic template.
Currently I have this:
template <typename T>
class A
{
public:
A(T t) : mT(t) {}
virtual ~A() {}
virtual void doThings() = 0;
protected:
T mT;
};
template <typename T, typename A = A<T>>
class B : public A
{
public:
B(T t) : A(t) {}
virtual ~B() {}
virtual void doThings() { std::cout << "B" << std::endl; }
};
template <typename T, typename A = A<T>>
class C : public A
{
public:
C(T t) : A(t) {}
virtual ~C() {}
virtual void doThings() { std::cout << "C" << std::endl; }
};
Now I thought I could do something like this, which obviously does not work:
template <typename T, typename ...Args>
class ChildGenerator : public Args...
{
public:
ChildGenerator(T t) : Args(t)... {}
// The unpacking of the variadic template does not work here.
// Do I need to make it recursive somehow? How can I do that without having to instantiate new classes B and C?
void doThings() override { Args...::doThings();}
};
My hope is that I can use it like so:
int main()
{
using B = B<double>;
using C = C<double>;
B c1(0.0);
C c2(1.0);
ChildGenerator<double, B, C> c3(2.0);
c1.doThings();
c2.doThings();
c3.doThings();
}
Expected output (order does not matter):
B
C
B // <-- order of these two does not matter
C // <--
Is what I'm trying to achieve possible?
One way to iterate over the variadic bases:
template <typename T, typename ...Args>
class ChildGenerator : public Args...
{
public:
ChildGenerator(T t) : Args(t)... {}
void doThings() override {
int dummy[] = {0, (Args::doThings(), void(), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable
}
};
or in C++17, with folding expression:
void doThings() override {
(static_cast<void>(Args::doThings()), ...);
}
Use a fold-expression (C++17):
void doThings() override { ((Args::doThings()) , ...);}
Live demo
I'm searching for a way to delegate trait functionality to member. Inheritance is not an option at this point.
So assume we have a class B and 2 different Traits already working with that class.
struct B
{};
template<typename T>
struct Trait1
{
static
void foo1(T t)
{}
};
template<>
struct Trait1<B>
{
static
void foo1(B t)
{}
};
template<typename T>
struct Trait2
{
static
void foo2(T t)
{}
};
template<>
struct Trait2<B>
{
static
void foo2(B t)
{}
};
I also have an aggregate class C with 2 members of that class B, like:
struct C
{
B m1;
B m2;
};
Now I want to define the both Traits for that class C as well, with delegating to the appropriate member. The plain approach would be s.th. like:
template<>
struct Trait1<C>
{
static
void foo1(C t)
{
Trait1<B>::foo1(t.m1);
}
};
template<>
struct Trait2<C>
{
static
void foo2(C t)
{
Trait2<B>::foo2(t.m2);
}
};
For traits with a lot of functions that is kind of annoying and probably has copy-paste errors. So the question arised to me, is there a way to delegate the functionality in an elegant way (C++11 preferred, C++14/17 also possible)? Meaning In case of Trait1 use member m1 and for Trait2 use member m2.
Thanks for help.
EDIT: methods of the Trait1 and Trait2 have actually different names.
And in the wild a macro replacing 1 with 2 will not work, so I would encourage not to use macros.
You can create a generic traits for factorize code
template<template <typename> class Trait, typename T, typename T2, T2 (T::*M)>
struct GenTrait
{
static
void foo(T t)
{
Trait<T2>::foo(t.*M);
}
};
And then
template<>
struct Trait1<C> : GenTrait<Trait1, C, B, &C::m1> {};
template<>
struct Trait2<C> : GenTrait<Trait2, C, B, &C::m2> {};
First, I needed executor template functions. These are the ones to do perform whatever has to be done and to be specialised or overloaded for other classes:
template<typename T>
void theFoo1(T t)
{
std::cout << "foo 1" << std::endl;
}
template<typename T>
void theFoo2(T t)
{
std::cout << "foo 2" << std::endl;
}
struct B
{};
void theFoo1(B t)
{
std::cout << "foo 1 B" << std::endl;
}
void theFoo2(B t)
{
std::cout << "foo 2 B" << std::endl;
}
Then, I need getter templates that provide the appropriate data:
template<typename T>
inline T get1(T t)
{
return t;
}
template<typename T>
inline T get2(T t)
{
return t;
}
My traits no look like this; note: you won't specialise these any more at any time:
template<typename T>
struct Trait1
{
static inline
void foo(T t)
{
theFoo1(get1(t));
}
};
template<typename T>
struct Trait2
{
static inline
void foo(T t)
{
theFoo2(get2(t));
}
};
Now C comes into play; B is already ready for use, so we can simply continue with C itself; all I need is two additional overloads:
struct C
{
B m1;
B m2;
};
B get1(C t)
{
return t.m1;
}
B get2(C t)
{
return t.m2;
}
Finally: test it...
int main(int, char*[])
{
B b;
Trait2<B>::foo(b);
C c;
Trait1<C>::foo(c);
Trait2<C>::foo(c);
}
Due to your specific requirement (where you need m1 & m2), there is no way to avoid re-writing lot of code for class C separately. To avoid such copy pasting, you may use simple macros. Pseudo code:
#define TRAIT_C(N, FUNCTION) \
template<> \
struct Trait##N<C> \
{ \
static \
void foo(C t) \
{ \
Trait##N<B>::foo(t.m##N); \
} \
}
Now use this in a "eye-soothing" way while defining trait for B:
template<>
struct Trait1<B>
{
static
void foo(B t)
{}
};
TRAIT_C(1, foo); // This inlines the complete version of `Trait1` for `C`
Here is a demo-ideone or demo-coliru.
You can expose the pointers to data members as part of the traits itself.
It can be done by means of template variables (named data in the example below).
It follows a minimal, working example:
struct B {};
template<typename T>
struct Trait1;
template<>
struct Trait1<B>
{
template<typename U>
static constexpr B U::* data = &U::m1;
static
void foo(B t)
{}
};
template<typename T>
struct Trait2;
template<>
struct Trait2<B>
{
template<typename U>
static constexpr B U::* data = &U::m2;
static
void foo(B t)
{}
};
struct C
{
B m1;
B m2;
};
template<>
struct Trait1<C>
{
using BT = Trait1<B>;
static constexpr B C::* data = BT::data<C>;
static
void foo(C t)
{
BT::foo(t.*data);
}
};
template<>
struct Trait2<C>
{
static
void foo(C t)
{
Trait2<B>::foo(t.*Trait2<B>::data<C>);
}
};
In the example above, Trait1<C> and Trait2<C> differ in order to show two possible solutions (I would use the first one if I had the same problem).
After inspiration by some of the proposals (e.g. #Aconcagua ) I thought of a DelegateTrait itself, like:
#include <iostream>
template<typename TraitT, typename DelegateT>
struct DelegateTrait
{
typedef DelegateT MemberT;// type of member delegated to
// method for delegation to specific member
static
MemberT forward(DelegateT delegate)
{
return delegate;
}
};
Now a small adaption of the original Trait1 is needed
template<typename T, typename DelegateT = void>
struct Trait1
{
static
void foo1(T t)
{
std::cout << "default Trait1<T>::foo1()" << std::endl;
}
};
template<typename T>
struct Trait1<
T,
typename std::enable_if<!std::is_same<T, typename DelegateTrait<Trait1<T>, T>::MemberT>::value>::type>
{
static
void foo1(T t)
{
std::cout << "delegate Trait1<T>::foo1()" << std::endl;
Trait1<typename DelegateTrait<Trait1<T>, T>::MemberT>::foo1(DelegateTrait<Trait1<T>, T>::forward(t));
}
};
template<>
struct Trait1<B>
{
static
void foo1(B t)
{
std::cout << "Trait1<B>::foo1()" << std::endl;
}
};
In a similar way an adaption of Trait2 is done. The std::enable_if is used to avoid recursive (and endless) calling of the same method.
You now have to specialize the DelegateTrait for each combination of class and trait where you want to forward to s.th. else but the instance of the given class.
template<>
struct DelegateTrait<Trait1<C>, C>
{
typedef B MemberT;
static
MemberT forward(C delegate)
{
std::cout << "forward C to C.m1" << std::endl;
return delegate.m1;
}
};
template<>
struct DelegateTrait<Trait2<C>, C>
{
typedef B MemberT;
static
MemberT forward(C delegate)
{
std::cout << "forward C to C.m2" << std::endl;
return delegate.m2;
}
};
You can still specialize for the class itself if you don't want to forward, like:
struct D
{
D(){};
B m1;
B m2;
};
template<>
struct Trait2<D>
{
static
void foo2(D t)
{
std::cout << "Trait<D>::foo2(), no delegate" << std::endl;
}
};
int
main(
int argc,
char ** argv)
{
C c;
Trait1<C>::foo1(c);//delegates to m1
Trait2<C>::foo2(c);//delegates to m2
D d;
Trait1<D>::foo1(d);//default trait implementation
Trait2<D>::foo2(d);//trait specialization for D
return 0;
}
Of course that solution needs a extension of the original trait. Do you see some other issue coming with that approach, e.g. performance?
I have a struct defined as follows:
struct A : public B, public C
{
A(const B& b) : B(b), C()
{}
template<typename... Args>
A(Args&&... args) : B(), C(std::forward<Args>(args)...)
{}
};
int main()
{
B b;
A sample1(b);
A sample2(3); // For example, B has a B(int) constructor.
}
And this doesn't work fine, because, A(b) tries use the second constructor (the non-constant reference is the preferred option, and the first constructor is a constant reference), but B hasn't any B(A&).
And moreover, I want to add a move constructor for B:
struct A : public B, public C
{
A(const B& b) : B(b), C()
{}
A(B&& b) : B(std::move(b)), C()
{}
template<typename... Args>
A(Args&&... args) : B(), C(std::forward<Args>(args)...)
{}
};
Now, the last step is to fusion the first two constructors:
struct A : public B, public C
{
template<typename fw_B>
A(fw_B&& b) : B(std::forward<fw_B>(b)), C()
{}
template<typename... Args>
A(Args&&... args) : B(), C(std::forward<Args>(args)...)
{}
};
Question: if the first version causes collision, the last version (my final purpose) its clear that it doesn't work also. How could I achieve this goal?
A possible solution would be use std::enable_if with std::is_convertible to only include the first constructor if the type of argument b is convertible to B:
template <
class fw_B,
class = typename std::enable_if<std::is_convertible<fw_B, B>::value, T>::type>
A(fw_B&& b)
For example:
#include <iostream>
#include <type_traits>
struct B
{
B() {}
B(int) {}
};
struct C {};
struct A : B, C
{
template <
class T,
class = typename std::enable_if<std::is_convertible<T, B>::value, T>::type>
A(T&& t) { std::cout << "A(T&&)\n"; }
template <class... TArgs>
A(TArgs&&... targs) { std::cout << "A(TArgs&&)\n"; }
};
int main()
{
B b;
A a1(b);
A a2(4);
A a3("hello");
return 0;
}
Output:
A(T&&)
A(T&&)
A(TArgs&&)
See demo at http://ideone.com/xJEjic .