具有模板函数名称和传递参数和 return 值的可变参数模板
variadic templates with template function names and passing arguments and return values around
根据 问题,我一直在尝试创建一个模板函数来调用其混入的所有同名方法。这已在上一个问题中完成并验证。
现在我正在尝试获取 SensorType::
的 return 值
分析:
#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();
}
}
以上编译并运行良好。问题是:如何从 运行 中的混合 SensorType::printStats()
方法 BaseSensor::printStats()
中收集 return 值(std::strings)?
如果我尝试创建 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()
中获取 return 值?
这是您的代码,已按照要求工作:
#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
class。这按预期工作,printStats
方法返回的字符串现在收集在 std::vector
中并返回给调用者。
将解决方案扩展到您可以做的任何类型的成员函数(实际上稍微简化了它,但仍要牢记 c++11 限制)。该方法解析成员函数的类型,以便能够推断其结果类型。它还使用 InferOwnerType
来推断混合类型并避免直接传递静态转换的 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,所以应该没问题
根据
现在我正在尝试获取 SensorType::
的 return 值分析:
#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();
}
}
以上编译并运行良好。问题是:如何从 运行 中的混合 SensorType::printStats()
方法 BaseSensor::printStats()
中收集 return 值(std::strings)?
如果我尝试创建 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()
中获取 return 值?
这是您的代码,已按照要求工作:
#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
class。这按预期工作,printStats
方法返回的字符串现在收集在 std::vector
中并返回给调用者。
将解决方案扩展到您可以做的任何类型的成员函数(实际上稍微简化了它,但仍要牢记 c++11 限制)。该方法解析成员函数的类型,以便能够推断其结果类型。它还使用 InferOwnerType
来推断混合类型并避免直接传递静态转换的 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,所以应该没问题