following this question , I am trying to avoid copy-pasting some code related to calling all of the same-named methods of the mixins of the class BaseSensor
.
Here is another, more compact solution that compiles in C++11:
#include <type_traits>
#include <iostream>
struct EdgeSensor {
void update() { std::cout << "EdgeSensor::update" << std::endl; }
void printStats() { std::cout << "EdgeSensor::printStats" << std::endl; }
};
struct TrendSensor {
void update() { std::cout << "TrendSensor::update" << std::endl; }
void printStats() { std::cout << "TrendSensor::printStats" << std::endl; }
};
template<typename ... SensorType>
class BaseSensor : public SensorType ... {
template <void(SensorType::* ...M)()>
void run() {
int arr[] = { 0, ((this->*M)(), 0)... };
(void)arr;
}
public:
void update() {
run<&SensorType::update...>();
}
void printStats() {
run<&SensorType::printStats...>();
}
};
int main() {
BaseSensor<EdgeSensor, TrendSensor> bs;
bs.update();
bs.printStats();
}
I would be tempted to say that you don't need any structure to support the pack of pointers to member methods.
Anyway, I found that this compiles with clang and it doesn't work with GCC. I'm still trying to figure out if the code is ill-formed or if the problem is in the compiler.
I'd suggest to follow the other question to know if you can use or not this code.
Yet another pure c++11 answer which came to my mind. This one uses tag dispatching and non-type template parameters:
template <class T, void (T::*)()>
struct Method { };
template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
template <class T, void(T::*M)()>
int runSingle(Method<T, M>) {
(this->*M)();
return 0;
}
template <class... Ts>
void runAll() {
int run[sizeof...(Ts)] = { runSingle(Ts{})... };
(void)run;
}
public:
void update() {
runAll<Method<SensorType, &SensorType::update>...>();
}
void printStats() {
runAll<Method<SensorType, &SensorType::printStats>...>();
}
};
It has to be stated though that non of these answers apart from the fold expressions (including skypjack's one) would deal with the virtual callee method of a mixin class... However I think skypjack answer could be easily modified to achieve such an effect:
#include<type_traits>
// (...)
template<typename ... SensorType>
class BaseSensor : public SensorType ...
{
template<typename F>
void execute(F &&f) {
int arr[] = { (f(static_cast<SensorType&>(*this)), 0)..., 0 };
(void)arr;
}
public:
void update() {
execute([](auto &t) { t.std::remove_reference<decltype(t)>::type::update(); });
}
void printStats() {
execute([](auto &t) { t.std::remove_reference<decltype(t)>::type::printStats(); });
}
};
Another c++11
way could be to use std::array
of pointer to method e.g.:
template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
void runAll(std::array<void (BaseSensor::*)(), sizeof...(SensorType)>&& vs) {
for (auto v: vs) {
(this->*v)();
}
}
public:
void update() {
runAll({&SensorType::update...});
}
void printStats() {
runAll({&SensorType::printStats...});
}
};
You can use a generic lambda and a kind of inversion of control.
It follows a minimal, working example:
#include<iostream>
struct EdgeSensor
{
void update() { std::cout << "EdgeSensor::update" << std::endl; }
void printStats() { std::cout << "EdgeSensor::printStats" << std::endl; }
};
struct TrendSensor
{
void update() { std::cout << "TrendSensor::update" << std::endl; }
void printStats() { std::cout << "TrendSensor::printStats" << std::endl; }
};
template<typename ... SensorType>
class BaseSensor : public SensorType ...
{
template<typename F>
void execute(F &&f) {
int arr[] = { (f(static_cast<SensorType&>(*this)), 0)..., 0 };
(void)arr;
}
public:
void update() {
execute([](auto &t) { t.update(); });
}
void printStats() {
execute([](auto &t) { t.printStats(); });
}
};
int main() {
BaseSensor<EdgeSensor,TrendSensor> ets;
ets.update();
ets.printStats();
}
If you can use c++1z fold expressions would probably be the shortest way:
template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
public:
void update() { (SensorType::update(),...); }
void printStats() { (SensorType::printStats(),...); }
};