简体   繁体   English

具有模板函数名称和传递参数以及返回值的可变参数模板

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

following from this question, I have been trying to create a template function that calls all same-named methods of its mixins. 这个问题之后,我一直在尝试创建一个模板函数,该函数调用其mixin的所有同名方法。 This has been done and verified in the previous question. 这已在前一个问题中完成并得到验证。

Now I am attempting to get the return value of SensorType:: 现在我试图获取SensorType ::的返回值

Analytically: 分析:

#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 <class T, void (T::*)(const int)>
struct Method { };

template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
   template <class T, void(T::*M)(const int)>
   int runSingle(Method<T, M> , const int i) {
      (this->*M)(i);
      return 0;
   }

   template <class... Ts>
   void runAll(const int i) {
      int run[sizeof...(Ts)] = { runSingle(Ts{},i)... };
      (void)run;
   }

public:
    void update() {
       runAll<Method<SensorType, &SensorType::update>...>(2);
    }
    void updat2() {
       const int k = 3;
       runAll<Method<SensorType, &SensorType::updat2>...>(k);
    }
    void printStats() {
    //   runAll<Method<SensorType, &SensorType::printStats>...>();
    }
};

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

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

The above compiles and runs fine. 以上编译并运行良好。 The problem is: how can I gather the return values (std::strings) from running the mixin SensorType::printStats() methods in BaseSensor::printStats() ? 问题是:如何从BaseSensor::printStats()运行mixin SensorType::printStats()方法收集返回值(std :: strings BaseSensor::printStats()

If I try to create a 2ndary version of the run* functions and the Method template, I fail to make it compile. 如果我尝试创建run*函数和Method模板的第二版,我就无法编译它。 Say I did: 说我做了:

template <class T, void (T::*)()>
struct Method2 { };

template <class T, void(T::*M)()>
int runSingle2(Method2<T, M>) {
    (this->*M)();
    return 0;
}

template <class... Ts>
void runAll2() {
    std::string s;
    int run[sizeof...(Ts)] = { s = runSingle2(Ts{})... };
    (void)run;
    std::cout << "s=" << s << std::endl;
}

public:
    void update() {
        int k = 4;
        runAll<Method<SensorType, &SensorType::update>...>(k);
    }
    void printStats() {
        runAll2<Method2<SensorType, &SensorType::printStats>...>();
    }
};

This does not compile saying 这不会编译说

g++ -Wall -Wextra -g -std=c++11   -c -o "obj_dbg/main.opp" "main.cpp"
main.cpp: In instantiation of ‘void BaseSensor<SensorType>::printStats() [with SensorType = EdgeSensor, TrendSensor]’:
main.cpp:65:20:   required from here
main.cpp:58:8: error: could not convert template argument ‘&EdgeSensor::printStats’ to ‘void (EdgeSensor::*)()’
make: *** [obj_dbg/main.opp] Error 1

So HOW can I grab the return values from SensorType::printStats() ? 那么我如何从SensorType::printStats()获取返回值?

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. 我重构了一些代码,因为不需要Method类。 This works as intended and the strings returned by the printStats methods are now collected in a std::vector and returned to the caller. 这按预期工作, printStats方法返回的字符串现在收集在std::vector并返回给调用者。

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). 要将解决方案扩展到您可以做的任何类型的成员函数(实际上有点简化它仍然考虑到c ++ 11限制)。 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. 它还使用InferOwnerType来推断mixin类型,并避免直接传递静态转换this指针。 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. 根据成员函数的结果,我们现在可以将它存储到数组中,或者使用int数组的技巧,以确保调用每个成员函数。

#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);
}

Not sure if you can use c++11, if so, then I think this is the easiest? 不确定你是否可以使用c ++ 11,如果是这样,那么我认为这是最简单的吗?

#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 注意:我在这里使用gcc扩展,但我认为你正在使用gcc,所以它应该没问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM