variadic templates with template function names and passing arguments and return values around

家住魔仙堡 提交于 2019-12-06 01:40:04

Not sure if you can use c++11, if so, then I think this is the easiest?

#include <iostream>
#include <string>

struct EdgeSensor
{
    void update(int i) { std::cout << "EdgeSensor::update " << i <<  std::endl; }
    void updat2(const int i ) { std::cout << "EdgeSensor::updat2" << i << std::endl; }
    std::string printStats() { std::cout << "EdgeSensor::printStats" << std::endl; 
                               return std::string("EdgeSensor::printStats"); }
};

struct TrendSensor
{
    void update(int i ) { std::cout << "TrendSensor::update" << i << std::endl; }
    void updat2(const int i ) { std::cout << "TrendSensor::updat2" << i << std::endl; }
    std::string printStats() { std::cout << "TrendSensor::printStats" << std::endl; 
                               return std::string("TrendSensor::printStats"); }
};

template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
public:
    void update() {
       auto v = { (static_cast<SensorType*>(this)->update(1), 0)... }; // *
       (void) v;
    }
    void updat2() {
       const int k = 3;
       auto v = { (static_cast<SensorType*>(this)->updat2(k), 0)... }; // *
       (void) v;
    }
    void printStats() {
       auto v = { static_cast<SensorType*>(this)->printStats()... };
       for (auto s : v) {
           std::cout << s << std::endl;
       }
    }
};

int main() {
  {
    BaseSensor<EdgeSensor,TrendSensor> ets;
    ets.update();
    ets.updat2();
    ets.printStats();
  }

  {
    BaseSensor<EdgeSensor> ets;
    ets.update();
    ets.updat2();
    ets.printStats();
  }
}
  • NOTE: I am using a gcc extension here, but I think you are using gcc, so it should be okay

Here is you code reviewed so as it works as requested:

#include<iostream>
#include <string>
#include <vector>

struct EdgeSensor
{
    void update(int i) { std::cout << "EdgeSensor::update " << i <<  std::endl; }
    void updat2(const int i ) { std::cout << "EdgeSensor::updat2" << i << std::endl; }
    std::string printStats() { std::cout << "EdgeSensor::printStats" << std::endl; 
    return std::string("EdgeSensor::printStats"); }
};

struct TrendSensor
{
    void update(int i ) { std::cout << "TrendSensor::update" << i << std::endl; }
    void updat2(const int i ) { std::cout << "TrendSensor::updat2" << i << std::endl; }
    std::string printStats() { std::cout << "TrendSensor::printStats" << std::endl; 
    return std::string("TrendSensor::printStats"); }
};

template<typename ... SensorType>
class BaseSensor : public SensorType ... {
    template<typename F>
    struct Invoke;

    template<typename R, typename... A>
    struct Invoke<R(A...)> {
        template <R(SensorType::* ...M)(A...), typename T>
        static std::vector<R> run(T *t, A... args) {
            std::vector<R> vec;
            int arr[] = { (vec.push_back((t->*M)(args...)), 0)... };
            (void)arr;  
            return vec;
        }
    };

    template<typename... A>
    struct Invoke<void(A...)> {
        template <void(SensorType::* ...M)(A...), typename T>
        static void run(T *t, A... args) {
            int arr[] = { ((t->*M)(args...), 0)... };
            (void)arr;  
        }
    };

public:
    void update() {
       Invoke<void(int)>::template run<&SensorType::update...>(this, 2);
    }
    void updat2() {
       const int k = 3;
       Invoke<void(int)>::template run<&SensorType::updat2...>(this, k);
    }
    void printStats() {
         auto vec = Invoke<std::string(void)>::template run<&SensorType::printStats...>(this);
         for(auto &&v: vec) {
             std::cout << "--->" << v << std::endl;
        }
    }
};

int main() {
  {
    BaseSensor<EdgeSensor,TrendSensor> ets;
    ets.update();
    ets.updat2();
    ets.printStats();
  }

  {
    BaseSensor<EdgeSensor> ets;
    ets.update();
    ets.updat2();
    ets.printStats();
  }
}

I refactored a bit the code, for there was no need for the Method class. This works as intended and the strings returned by the printStats methods are now collected in a std::vector and returned to the caller.

To extend the solution to any type of member function you could do (and actually a bit simplify it still having in mind c++11 restriction). The approach resolves type of member function to be able to infer its result type. It also uses InferOwnerType to infer mixin type and avoid direct passing of statically casted this pointer. Depending on the result of the member function now we can store it into an array or use the trick with int array just to be sure each member function is invoked.

#include <iostream> // std::cout std::endl
#include <string>   // std::string
#include <utility>  // std::declval

struct EdgeSensor //a mixin
{
    void update(int a){ std::cout << "EdgeSensor::update" << a << std::endl; }
    std::string updat2(int const v) { return "EdgeSensor::printStats"; }
};

struct TrendSensor //another mixin
{
    void update(int a){ std::cout << "TrendSensor::update" << std::endl; }
    std::string updat2(int const v) { return "TrendSensor::printStats"; }
};

template <class Res, class This, class... Args>
This InferOwnerType(Res (This::*foo)(Args...)) { }

template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
    template <class M, class... Args>
    auto run(M m, Args... args)
       -> decltype((std::declval<decltype(InferOwnerType(m))*>()->*m)(args...)) {
       return (static_cast<decltype(InferOwnerType(m))*>(this)->*m)(args...);
    }

public:
    template <class... Args>
    void update(Args... args) {
       int arr[] = {(run(&SensorType::update, args...), 0)...};
       (void)arr;
    }
    template <class... Args>
    void updat2(Args... args) {
       std::string s[] = {run(&SensorType::updat2, args...)...};
       for (int i = 0; i < sizeof...(SensorType); i++)
          std::cout << s[i] << std::endl;
    }
};

int main() {
   BaseSensor<EdgeSensor, TrendSensor> bs;
   bs.update(4);
   bs.updat2(0);
   BaseSensor<EdgeSensor> bs2;
   bs2.update(1);
   bs2.updat2(0);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!