5

So I've been trying to use variadic templates to compose objects out of more convenient subtypes, but I'm having trouble getting it to do exactly what I want.

template<class ...Functor>
struct SeqMethod:public Functor...{
  template<class F>
  void call(F& a){
    F::operator()();
  }
  template<class F,class ... funcs>
  void call(){
    F::operator()();

    call<funcs...>();
  }
  public:
  void operator()(){
    call<Functor...>();
  }
};

This isn't valid syntax, so there's that.

Ideally I'd like to be able to use something like this

class A{
public:
  void operator()(){
    std::cout<<"A";
  }
};
class B{
public:
  void operator()(){
    std::cout<<"B";
  }
};

class C:public SeqMethod<A,B>{};

Which in this case should output "AB", and in general be suitable for composing behaviors together.

violet_white
  • 404
  • 2
  • 15

2 Answers2

6

You don't actually need any call member function in your case.
Instead you can do this in C++11/C++14:

template<class ...Functor>
struct SeqMethod:public Functor...{
  public:
  void operator()(){
      int _[] = { (Functor::operator()(), 0)... };
      return void(_);
  }
};

It follows a minimal, working example:

#include<iostream>

template<class ...Functor>
struct SeqMethod:public Functor...{
  public:
  void operator()(){
    int _[] = { (Functor::operator()(), 0)... };
    return void(_);
  }
};

class A{
public:
  void operator()(){
    std::cout<<"A";
  }
};
class B{
public:
  void operator()(){
    std::cout<<"B";
  }
};

class C:public SeqMethod<A,B>{};

int main() {
  C c;
  c();
}
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 1
    C++17 changed things a bit. This is the C++14 way to unroll a parameters pack. SO as well as the web are full of in-depth explanations for it, more detailed than what I could in a comment. ;-) – skypjack May 23 '19 at 13:34
  • thanks for quick reply. I know about the fold expression in C++17. But currently I'm using C++11, and all i could find is implementation like question. Can you send some keywords i should look for and is it possible to do this without declaring an array ? Thanks again. – s0nskar May 23 '19 at 13:52
  • 1
    You should search for unpacking parameter pack in C++11 or something like this. In general, an array like thing is required btw. – skypjack May 23 '19 at 13:53
3

The easiest way to do this is with C++17's fold expressions:

template<class ...Functor>
struct SeqMethod:public Functor...{

 public:
    void operator()(){
        (Functor::operator()(),...);
    }
};

class A{
public:
    void operator()(){
        std::cout<<"A";
    }
};
class B{
public:
    void operator()(){
        std::cout<<"B";
    }
};

class C:public SeqMethod<A,B>{};

int main()
{
    C c;
    c();
    return 0;
}

Output (tested with gcc 6.2):

AB
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • This is great, I really appreciate this option, but I'm working on some platforms whose c++ compilers are a bit outdated, so since the other option(the initializer list hack) is a bit easier to come by as far as support goes. – violet_white Dec 24 '16 at 00:01