Definite methods with parameters from variadic templates - c++

I would like to define a variadic template class BaseA, which has a variadic function execute(...). The subclasses extend execute(...) with definite arguments.
I try a demo code, but it has type conversion error, how to collect all subclasses and use execute?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// template base class A
template <typename ... Types>
class BaseA {
public:
virtual int execute(Types ...) = 0;
};
// subclass 1
class SubA1 :public BaseA<int> {
public:
int execute(int b) override {
//...
printf("sub-1 has int %d", b);
return 0;
}
};
// subclass 2
class SubA2 :public BaseA<int, string> {
public:
int execute(int b, string c) override {
//...
printf("sub-2 is int:%d and str:%s", b, c.c_str());
return 0;
}
};
// SubA3 may has other arguments
int main() {
vector<BaseA<int> *> as(3);
as[0] = (BaseA<int> *) new SubA1();
as[1] = (BaseA<int, string> *) new SubA2(); // error here
as[0]->execute(1);
as[1]->execute(1, "2");
// as[2] ...
return 0;
}
Thanks for any ideas.

Use another base for the array and typecast when using.
#include <iostream>
#include <string>
#include <vector>
class BaseAA {
public:
BaseAA(){
}
~BaseAA(){
}
template <typename ... Types>
int executeAA(Types ...){
std::cout << "BaseAA";
return 0;
}
};
// template base class A
template <typename ... Types>
class BaseA: public BaseAA {
public:
using BaseType = BaseA<Types...>;
virtual int execute(Types ... ts){
std::cout << "BaseA ";
return executeAA<Types ...>(ts...);
};
};
// subclass 1
class SubA1 :public BaseA<int> {
public:
int execute(int b) override {
//...
BaseType::execute(b);
std::cout << "sub-1 has int " << b << '\n';
return 0;
}
};
// subclass 2
class SubA2 :public BaseA<int, std::string> {
public:
int execute(int b, std::string c) override {
//...
BaseType::execute(b, c);
std::cout << "sub-2 is int:"<<b<<" and str:" << c;
return 0;
}
};
// SubA3 may has other arguments
int main() {
std::vector<BaseAA *> as(3);
as[0] = new SubA1();
as[1] = new SubA2(); // error here
static_cast<SubA1::BaseType*>(as[0])->execute(1);
static_cast<SubA2::BaseType*>(as[1])->execute(1, "2");
// as[2] ...
return 0;
}
If you don't want the typecast then you can use a single parameter type
with derived classes for the different groups of parameters.
#include <iostream>
#include <vector>
#include <tuple>
using namespace std::string_literals;
template <class O, class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_this(O* o, F&& f, Tuple&& t, std::index_sequence<I...>) {
return (o->*f)(std::get<I>(t)...);
}
struct ParamsBase {
};
class BaseAA {
public:
BaseAA(){
}
~BaseAA(){
}
virtual int execute(const ParamsBase& p) = 0;
};
template<typename ... Ts>
struct Params: public ParamsBase {
using Tuple_t = std::tuple<Ts...>;
static size_t const count = sizeof ... (Ts);
Tuple_t p;
Params(Tuple_t&& p): p(p){
}
static Params const& getParams(const ParamsBase& p) {
return static_cast<const Params&>(p);
}
static Tuple_t const& getTuple(const ParamsBase& p) {
return getParams(p).p;
}
};
// template base class A
template <typename ... Types>
class BaseA: public BaseAA {
public:
using Params_t = Params<Types...>;
virtual int execute(const ParamsBase& pin) override {
return apply_this(this, (int(BaseA::*)(Types...))(&BaseA::execute), Params_t::getTuple(pin), std::make_index_sequence<Params_t::count>{});
}
virtual int execute(Types ... t){
std::cout << " default ";
return 0;
}
};
// subclass 1
class SubA1 :public BaseA<int> {
public:
virtual int execute(int b) override {
BaseA::execute(b);
std::cout << " sub-1 has int " << b << '\n';
return 0;
}
};
// subclass 2
class SubA2 :public BaseA<int, std::string> {
public:
virtual int execute(int b, std::string c) override {
BaseA::execute(b, c);
std::cout << " sub-2 is int: "<<b<<" and str: " << c;
return 0;
}
};
// SubA3 may has other arguments
int main() {
std::vector<BaseAA *> as(3);
as[0] = new SubA1();
as[1] = new SubA2();
as[0]->execute(Params(std::make_tuple(1)));
as[1]->execute(Params(std::make_tuple(1, "2"s))); // s makes std::string
// as[2] ...
return 0;
}
https://godbolt.org/z/tueU2f

When you create a
vector<BaseA<> *> as(2);
you are expecting that vector can accept any type. Which is, I believe, wrong in C++. The vector can accept only type.
When you use template to instantiate the Base class type, the compiler will generate following class hierarchy for you.
class BaseA_int {
public:
virtual int execute(int) = 0;
};
// subclass 1
class SubA1 :public BaseA_int {
public:
int execute(int b) override {
//...
return 0;
}
};
class BaseA_int_string
{
public:
virtual int execute(int, string) = 0;
};
// subclass 2
class SubA2 :public BaseA_int_string {
int execute(int b, string c) override {
//...
return 0;
}
};
And here you can see that derived classes uses different base classes. As the vector can only one type, Base<> *, but your are assigning a type of Base to it, the compiler gives an error.
So Base and Base are entirely two different base classes.
The below will compile without any issue, but it cannot accept Base
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// template base class A
template <typename ... Types>
class BaseA {
public:
virtual int execute(Types ...) = 0;
};
// subclass 1
class SubA1 :public BaseA<int> {
int execute(int b) override {
//...
return 0;
}
};
// subclass 2
class SubA2 :public BaseA<int, string> {
int execute(int b, string c) override {
//...
return 0;
}
};
int main() {
vector<BaseA<int> *> as(2);
as[0] = (BaseA<int> *) new SubA1(); // type conversion error here
as[0]->execute(1);
return 0;
}

Related

Specialize member function of a templated derived class

I have the following code (very simplified for the sake of clarity):
class Base
{
virtual int DoStuff(int arg) = 0;
};
template <typename T>
class Derived : public Base
{
int DoStuff(int arg) override
{
// do some stuff
return 0;
}
};
This works great. Now I want to implement a special (vectorized) implementation of DoStuff. And I need the implementation to be specific based on the type T that Derived has, something like this:
class Base
{
virtual int DoStuff(int arg) = 0;
virtual int DoStuffVectorized(int arg) = 0;
};
template <typename T>
class Derived : public Base
{
int DoStuff(int arg) override
{
// do some stuff
return 0;
}
int DoStuffVectorized<char>(int arg) override
{
// do some stuff for T == char
return 0;
}
int DoStuffVectorized<int>(int arg) override
{
// do some stuff for T == int
return 0;
}
};
However i'm unable to make this work.
EDIT:
I get the following error message: error C2143: syntax error: missing ';' before '<' on the line int DoStuffVectorized<char>(int arg) override.
When i change it to:
template<char> int DoStuffVectorized(int arg) override i get: error C2898: ...': member function templates cannot be virtual
Any advice on how to achieve something like this? The reason i need it is that i have a std::vector that stores data of various types (by using Derived<>). This way i can use the same simple code regardless of the type being stored and i want this to be true even when using the special vectorized implementation of DoStuff that is sadly type specific.
You have to specialize template member functions outside of the class:
#include <iostream>
class Base
{
public:
virtual int DoStuffVectorized(int arg) = 0;
};
template <typename T>
class Derived : public Base
{
public:
int DoStuffVectorized(int arg) override;
};
template <>
int Derived<char>::DoStuffVectorized(int arg)
{
std::cout << "T == char\n";
return 0;
}
template <>
int Derived<int>::DoStuffVectorized(int arg)
{
std::cout << "T == int\n";
return 0;
}
int main(){
Derived<char> c;
Derived<int> i;
Base* b[] = { &c, &i };
for(auto* x : b)
x->DoStuffVectorized(0);
// undefined reference to `Derived<double>::DoStuffVectorized(int)'
// Derived<double> d;
}
If you want to capture unintended instantiations at compile time:
#include <type_traits>
// A std::false_type (useful in a static_assert)
template <typename T>
struct static_false : std::false_type
{};
template <typename T>
int Derived<T>::DoStuffVectorized(int arg)
{
static_assert(static_false<T>::value, "Neither 'char' or 'int'");
return 0;
}
DoStuffVectorized<char> is not correct syntax, DoStuffVectorized isn't template itself.
See template specialization:
template <typename T>
class Derived : public Base
{
int DoStuff(int arg) override
{
// do some stuff
return 0;
}
int DoStuffVectorized(int arg) override
{
// do some stuff (primary template)
return 0;
}
};
template <>
int Derived<int>::DoStuffVectorized(int) {
// do some stuff for T == char
return 0;
}
template <>
int Derived<char>::DoStuffVectorized(int) {
// do some stuff for T == char
return 0;
}

How to use different functoids within an array or vector

I have written a small piece of code where I am able to call setter and getter functions packed within a functoid using mem_fun templates.
I now would like to use this approach on top of a class hierarchy where every class might have getter and setter which can be registered as pair within a vector or array to be able to call the getter and setter if needed. GUIObject and GUICompositeObject are example classes out of the described class hierarchy.
The bound_mem_fun_t for the objects have unfortunately different types and thats the reason I don't know how to integrate them into an array/vector of pointers to the functors.
In c++11 I would use std::function. Is there a way to emulate this in c++98?
Because our compiler support only c++98 I cannot use the new features of c++11 or c++14. Also boost is not allowed.
#include <functional>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
template<typename T>
struct bound_mem_fun_t
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
int operator()() { return m_GetFunc(obj); } ;
void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
bound_mem_fun_t<GUIObject> GUIObjectFunc(std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject);
GUIObjectFunc(17);
int ii = GUIObjectFunc();
bound_mem_fun_t<GUICompositeObject> GUICompObjectFunc(std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj);
GUICompObjectFunc(17);
int iChilds = GUICompObjectFunc();
return 0;
}
Here is the complete solution after #filmors answer:
#include <functional>
#include <vector>
#include <iostream>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
struct bound_mem_fun_base
{
virtual int operator()() =0;
virtual void operator()(int) =0;
};
template<typename T>
struct bound_mem_fun_t : public bound_mem_fun_base
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
virtual int operator()() { return m_GetFunc(obj); } ;
virtual void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
template<typename T> bound_mem_fun_t<T>* make_setter(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o)
{
return new bound_mem_fun_t<T> (GetFunc, SetFunc, o);
}
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
std::vector<bound_mem_fun_base*> kBoundVector;
kBoundVector.push_back(new bound_mem_fun_t<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(new bound_mem_fun_t<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
kBoundVector.push_back(make_setter<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(make_setter<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
for (int i = 0; i < 4 ; i++)
{
(*kBoundVector[i])(i*10);
int res = (*kBoundVector[i])();
std::cout << "Getter result " << res << "\n";
}
return 0;
}
Unfortunately the make_setter function does not really shorten the creation of the functor. Any ideas will be welcome.
Just give your bound_mem_fun_t<T> a common base class and use dynamic dispatch to solve your problem:
struct bound_mem_fun_base {
virtual int operator()() = 0;
virtual void operator()(int) = 0;
};
template <typename T>
struct bound_mem_fun_t : bound_mem_fun_t ...
Then you can keep pointers to bound_mem_fun_base in your vector and call the elements as (*v[0])().
Also, TR1 does contain std::tr1::function, is that available?
First a remark on std::function from c++11: That will not solve your problem, because you need an already bounded function pointer. This pointer must be bound to your object. I believe what you need is an own implementation to std::bind.
I started only a very! small Binder class which is hopefully a starting point for your needs. If you need to have template parameter lists in older c++ versions, take a look for loki. http://loki-lib.sourceforge.net/
As a hint I can give you a short example of what i did:
class A
{
private:
int val;
public:
A(int i): val(i) {}
void Do(int i) { std::cout << "A " << val<< " " << i << std::endl; }
};
class B
{
private:
int val;
public:
B(int i): val(i){}
void Go(int i) { std::cout << "B " << val << " " << i << std::endl; }
};
class Base
{
public:
virtual void operator()(int i)=0;
};
template <typename T>
class Binder: public Base
{
void (T::*fnct)(int);
T* obj;
public:
Binder( void(T::*_fnct)(int), T*_obj):fnct(_fnct),obj(_obj){}
void operator()(int i)
{
(obj->*fnct)(i);
}
};
int main()
{
A a(100);
B b(200);
// c++11 usage for this example
//std::function<void(int)> af= std::bind( &A::Do, &a, std::placeholders::_1);
//af(1);
// hand crafted solution
Base* actions[2];
actions[0]= new Binder<A>( &A::Do, &a);
actions[1]= new Binder<B>( &B::Go, &b);
actions[0]->operator()(55);
actions[1]->operator()(77);
}

Virtual static variable

I need to assign unique integer value to each descendant of class Base that should be accessible by using pointer to those classes or its typenames.
I implemented it such way
class Base {
public:
int idCompType = InvalidCompType;
virtual int getCompType() = 0;
}
then in each descendant of base I should declare idCompType (for templates) and override getCompType (for pointers):
class Real1: public Base {
public:
int idCompType = 1;
int getCompType() override { return idCompType; }
}
now I can find comp type from pointer to base
Base *comp = getComp(...);
std::cout << comp->getCompType();
or using typename in template:
template <typename T>
int getType() {
return T::idCompType;
}
Is there a way to make it even simpler without double declaration idCompType and getCompType() in each descendant class? In Object Pascal I achieved this using virtual static methods, but their are not allowed in C++..
PS: the question is not about virtual static methods - virtual static method is just the one of the possible solutions and the way my problem was solved in other language.
My recommendation:
Changes to Base:
class Base {
public:
virtual int getCompType() = 0;
protected:
static int getNextCompType()
{
static int nextType = 0;
return ++nextType;
}
};
Changes to the derived class:
class Real1: public Base {
public:
static int getCompTypeImpl()
{
static int myType = Base::getNextCompType();
return myType;
}
int getCompType() override
{
return getCompTypeImpl();
}
};
Here's a working program:
#include <iostream>
class Base {
public:
virtual int getCompType() = 0;
protected:
static int getNextCompType()
{
static int nextType = 0;
return ++nextType;
}
};
class Real1: public Base {
public:
static int getCompTypeImpl()
{
static int myType = Base::getNextCompType();
return myType;
}
int getCompType() override
{
return getCompTypeImpl();
}
};
class Real2: public Base {
public:
static int getCompTypeImpl()
{
static int myType = Base::getNextCompType();
return myType;
}
int getCompType() override
{
return getCompTypeImpl();
}
};
template <typename T> int getCompType()
{
return T::getCompTypeImpl();
}
int main()
{
Real1 v1;
Real2 v2;
std::cout << v1.getCompType() << std::endl;
std::cout << v2.getCompType() << std::endl;
std::cout << getCompType<Real1>() << std::endl;
std::cout << getCompType<Real2>() << std::endl;
};
Output:
1
2
1
2
Here is a slight variant of #Sahu's version.
Instead of implementing the same getCompTypeImpl() in every derived class, put it in Base class.
template<typename T>
static int getCompTypeImpl()
{
return getNextCompType<T>();
}
Modify getNextCompType() to
template<typename T>
static int getNextCompType()
{
auto iter = m_table.find(std::type_index(typeid(T)));
if (iter != m_table.end())
{
return iter->second;
}
else
{
m_table.insert(std::make_pair(std::type_index(typeid(T)), ++nextType));
return nextType;
}
}
And finally introduce 2 new static data members.
private:
static std::map<std::type_index, int> m_table;
static int nextType;
Please find the full code here.
Admittedly this introduces 2 new static members and does a bit more work
than the original version from Sahu. But, this removes the burden of implementing the methods in
all the derived classes.
Yet another variation of #R Sahu's answer to eliminate duplication of code in the derived classes:
#include <iostream>
class Base {
public:
virtual int getCompType() const = 0;
template <typename T>
static int getCompTypeOf()
{
static int compType = getNextCompType();
return compType;
}
private:
static int getNextCompType()
{
static int nextType = 0;
return ++nextType;
}
};
template <typename Derived, typename DeriveFrom = Base>
class TypeAssigner : DeriveFrom {
public:
int getCompType() const override
{
return Base::getCompTypeOf<Derived>();
}
};
class Real1: public TypeAssigner<Real1> {};
class Real2: public TypeAssigner<Real2> {};
class Real3 : public TypeAssigner<Real3, Real2> {};
int main()
{
Real1 v1;
Real2 v2;
Real3 v3;
std::cout << v1.getCompType() << '\n';
std::cout << v2.getCompType() << '\n';
std::cout << v3.getCompType() << '\n';
std::cout << Base::getCompTypeOf<Real1>() << '\n';
std::cout << Base::getCompTypeOf<Real2>() << '\n';
std::cout << Base::getCompTypeOf<Real3>() << '\n';
};

Adding a template typename to two template classes

I have learned this code like inheritance by using template technique on C++. This code works.
#include <iostream>
using namespace std;
template < typename T >
class Base {
public:
explicit Base(const T& policy = T()) : m_policy(policy) {}
void doSomething()
{
m_policy.doA();
m_policy.doB();
}
private:
T m_policy;
};
class Implemented {
public:
void doA() { cout << "A"; };
void doB() { cout << "B"; };
};
int main() {
Base<Implemented> x;
x.doSomething();
return 0;
}
However, is it possible to add arguments with new typename S in doA and doB? For example, this code doesn't work by type/value mismatch errors.
#include <iostream>
using namespace std;
template < typename T, typename S >
class Base {
public:
explicit Base(const T& policy = T()) : m_policy(policy) {}
void doSomething()
{
m_policy.doA(m_s);
m_policy.doB(m_s);
}
private:
T m_policy;
S m_s;
};
template < typename S >
class Implemented {
public:
void doA(S& s) { cout << "A" << s; };
void doB(S& s) { cout << "B" << s; };
};
int main() {
Base<Implemented, int> x;
x.doSomething();
return 0;
}
I guess I must let both class Base and Implemented know about an actual type of S at main(). How can I fix this issue? Thank you for your help in advance.
In this line:
Base<Implemented, int> x;
Implemented is no longer a type, now you made it a template. But Base still expects a type - so give it one:
Base<Implemented<int>, int> x;
When Implemented was a class, you used a template parameter T. Now that Implmented is a template class, you need to use a so called template template parameter, like so:
#include <iostream>
using namespace std;
template < template <class TS> class T, typename S >
class Base {
public:
explicit Base(const T<S>& policy = T<S>()) : m_policy(policy) {}
void doSomething()
{
m_policy.doA(m_s);
m_policy.doB(m_s);
}
private:
T<S> m_policy;
S m_s;
};
template < typename S >
class Implemented {
public:
void doA(S& s) { cout << "A" << s; };
void doB(S& s) { cout << "B" << s; };
};
int main() {
Base<Implemented, int> x;
x.doSomething();
return 0;
}

Call different versions of template member function based on template paramaters

I need to call different versions of a template member function with the same arguments based on certain static members of the template parameters. Here's a sort of simplified version of what I need to do:
class A {
public:
//...
static const char fooString[];
};
const char A::fooString[] = "This is a Foo.";
class B {
public:
//...
static const char barString[];
};
const char B::barString[] = "This is a Bar.";
class C {
public:
//...
static const char fooString[];
};
const char C::fooString[] = "This is also a Foo.";
//Many other classes which have either a fooString or a barString
void doFoo(const char*s) { /*something*/ }
void doBar(const char*s) { /*something else*/ }
template&ltclass T>
class Something {
public:
//This version should be called if T has a static member called "fooString",
//so it should be called if T is either class A or C
void doSomething() { doFoo(T::fooString); }
//This version should be called if T has a static member called "barString",
//so it should be called if T is class B
void doSomething() { doBar(T::barString); }
};
void someFunc()
{
Something&ltA> a;
Something&ltB> b;
Something&ltC> c;
a.doSomething(); //should call doFoo(A::fooString)
b.doSomething(); //should call doBar(B::barString)
c.doSomething(); //should call doFoo(C::fooString)
}
How would I achieve this?
A possible solution:
#include <iostream>
#include <type_traits>
class A {
public:
//...
static const char fooString[];
};
const char A::fooString[] = "This is a Foo.";
class B {
public:
//...
static const char barString[];
};
const char B::barString[] = "This is a Bar.";
class C {
public:
//...
static const char fooString[];
};
const char C::fooString[] = "This is also a Foo.";
void doFoo(const char*s) { std::cout << "doFoo: " << s << "\n"; }
void doBar(const char*s) { std::cout << "doBar: " << s << "\n"; }
template<class T>
class Something {
public:
//This version should be called if T has a static member called "fooString",
//so it should be called if T is either class A or C
template <typename TT = T, typename std::enable_if<TT::fooString != 0, bool>::type = false>
void doSomething() { doFoo(T::fooString); }
//This version should be called if T has a static member called "barString",
//so it should be called if T is class B
template <typename TT = T, typename std::enable_if<TT::barString != 0, bool>::type = false>
void doSomething() { doBar(T::barString); }
};
int main()
{
Something<A> a;
Something<B> b;
Something<C> c;
a.doSomething(); //should call doFoo(A::fooString)
b.doSomething(); //should call doBar(B::barString)
c.doSomething(); //should call doFoo(C::fooString)
}
Output:
doFoo: This is a Foo.
doBar: This is a Bar.
doFoo: This is also a Foo.