簡體   English   中英

具有模板函數名稱和傳遞參數以及返回值的可變參數模板

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

這個問題之后,我一直在嘗試創建一個模板函數,該函數調用其mixin的所有同名方法。 這已在前一個問題中完成並得到驗證。

現在我試圖獲取SensorType ::的返回值

分析:

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

以上編譯並運行良好。 問題是:如何從BaseSensor::printStats()運行mixin SensorType::printStats()方法收集返回值(std :: strings BaseSensor::printStats()

如果我嘗試創建run*函數和Method模板的第二版,我就無法編譯它。 說我做了:

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>...>();
    }
};

這不會編譯說

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

那么我如何從SensorType::printStats()獲取返回值?

以下是您審核的代碼,以便按要求運行:

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

我重構了一些代碼,因為不需要Method類。 這按預期工作, printStats方法返回的字符串現在收集在std::vector並返回給調用者。

要將解決方案擴展到您可以做的任何類型的成員函數(實際上有點簡化它仍然考慮到c ++ 11限制)。 該方法解析了成員函數的類型,以便能夠推斷其結果類型。 它還使用InferOwnerType來推斷mixin類型,並避免直接傳遞靜態轉換this指針。 根據成員函數的結果,我們現在可以將它存儲到數組中,或者使用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);
}

不確定你是否可以使用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();
  }
}
  • 注意:我在這里使用gcc擴展,但我認為你正在使用gcc,所以它應該沒問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM