variadic templates with template function names

前端 未结 5 1105
悲哀的现实
悲哀的现实 2021-01-14 18:14

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.

相关标签:
5条回答
  • 2021-01-14 18:54

    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.

    0 讨论(0)
  • 2021-01-14 18:55

    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(); });
        }
    };
    
    0 讨论(0)
  • 2021-01-14 18:58

    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...});
        }
    };
    
    0 讨论(0)
  • 2021-01-14 18:59

    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();
    }
    
    0 讨论(0)
  • 2021-01-14 19:06

    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(),...); }
    };
    
    0 讨论(0)
提交回复
热议问题