3

I have a parameter pack full of default constructable and then callable objects (like the ExampleFunctor) and want to call all of them in order (left to right). If the return type is anything besides void I can use an initializer list to do this:

struct ExampleFunctor{
    void operator()(){someGlobal = 4;}
};

template<typename... Ts>
struct CallThem {
    void operator()(){
        auto list = {Ts()()...};
    }
}

however if the return type is void this trick does not work.

I could wrap all the Ts in a wrapper returning an int but that seems overkill and this code will be ultimately running on a cortex M3 with 32K of flash so the extra function call overhead of the wrapper is a pain if I compile the unit in debug mode (and debugging in release mode makes my brain hurt).

Is there a better way?

odinthenerd
  • 5,422
  • 1
  • 32
  • 61

3 Answers3

6

With the comma operator:

int someGlobal;

struct ExampleFunctor{
    void operator()(){someGlobal = 4;}
};

template<typename... Ts>
struct CallThem {
    void operator()(){
        int list[] = {(Ts()(),0)...};
        (void)list;
    }
};

int main()
{
    CallThem<ExampleFunctor, ExampleFunctor>{}();
}

Btw I'm not using an initializer_list here but just an array; try yourself which one / if any of them can be thrown away by the compiler. The (void)list is to suppress a warning (unused variable).

dyp
  • 38,334
  • 13
  • 112
  • 177
1

The compiler should be able to optimize away the function calls here:

template <typename H, typename... Tail>
void call(H head, Tail... tail) {
   head();
   call(tail...);
}
template <typename T>
void call(T fn) {
   fn();
}
template <typename... Args>
void callThem() {
   call(Args()...);
}

But this is untested. Check the generated assembly for your platform.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • yes is does optimize them away in release mode, I need the debug mode binary to fit in the chip though! I know this is a special case but thats why I stated it as one. – odinthenerd Nov 08 '13 at 14:16
0

You may use something like:

template<typename... Ts>
struct CallThem;

template<>
struct CallThem<> { void operator()() const {} };

template<typename Tail, typename... Queue>
struct CallThem<Tail, Queue...>
{
    void operator()() const {
        Tail()();
        CallThem<Queue...>()();
    }
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I know the compiler does optimize the recursive function call away in release mode, I need the debug mode binary to fit in the chip though! I know this is a special case but thats why I stated it as one. – odinthenerd Nov 08 '13 at 14:20