C++ 具有模板函数名的可变模板
下面的问题是,我试图避免复制粘贴一些与调用类C++ 具有模板函数名的可变模板,c++,templates,variadic-templates,C++,Templates,Variadic Templates,下面的问题是,我试图避免复制粘贴一些与调用类BaseSensor的mixin的所有相同命名方法相关的代码 in sensor.hpp struct EdgeSensor //a mixin { void update(){} void printStats() {} }; struct TrendSensor //another mixin { void update(){} void printStats() {} }; template<typena
BaseSensor
的mixin的所有相同命名方法相关的代码
in sensor.hpp
struct EdgeSensor //a mixin
{
void update(){}
void printStats() {}
};
struct TrendSensor //another mixin
{
void update(){}
void printStats() {}
};
template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
void update() /*{ what goes in here??? }*/
void printStats() /*{ what goes in here??? }*/
};
那么我如何从BaseSensor::update()
和BaseSensor::printStats()
调用它呢。我试图使用
void update() { runAll<update>(); }
void printStats() { runAll<printStats>(); }
这也不正确
在这种情况下可以避免复制吗?如果我将工作的runAll()
移动到文件“sensor.t.hpp”中,模板参数会是什么样子
谢谢您可以使用通用lambda和一种控制反转。
下面是一个简单的工作示例:
#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();
}
#包括
结构边缘传感器
{
void update(){std::cout如果可以使用c++1z折叠表达式,可能是最短的方法:
template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
public:
void update() { (SensorType::update(),...); }
void printStats() { (SensorType::printStats(),...); }
};
模板
class BaseSensor:public SensorType…//到我的BaseSensor类
{
公众:
无效更新(){(传感器类型::更新(),…);}
void printStats(){(传感器类型::printStats(),…);}
};
另一种c++11
方法可以是使用指向方法的指针的std::array
,例如:
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...});
}
};
模板
class BaseSensor:public SensorType…//到我的BaseSensor类
{
void runAll(std::array&&vs){
用于(自动v:vs){
(本->*v)();
}
}
公众:
无效更新(){
runAll({&SensorType::update…});
}
void printStats(){
runAll({&SensorType::printStats…});
}
};
我想到了另一个纯粹的c++11答案。这个答案使用标记分派和非类型模板参数:
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>...>();
}
};
模板
结构方法{};
模板
class BaseSensor:public SensorType…//到我的BaseSensor类
{
模板
int runSingle(方法){
(本->*M)();
返回0;
}
模板
void runAll(){
int run[sizeof…(Ts)]={runSingle(Ts{})…};
(无效)运行;
}
公众:
无效更新(){
runAll();
}
void printStats(){
runAll();
}
};
必须说明的是,除了fold表达式(包括skypjack的一个)之外,这些答案中没有一个会处理mixin类的虚拟被调用方方法……但是我认为skypjack答案可以很容易地修改以达到这样的效果:
#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(); });
}
};
#包括
// (...)
模板
类BaseSensor:公共传感器类型。。。
{
模板
无效执行(F&&F){
int arr[]={(f(static_cast(*this)),0)…,0};
(无效)arr;
}
公众:
无效更新(){
执行([](auto&t){t.std::remove_reference::type::update();});
}
void printStats(){
执行([](auto&t){t.std::remove_reference::type::printStats();});
}
};
下面是另一个用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();
}
#包括
#包括
结构边缘传感器{
无效更新(){std::cout lambda参数可能应该是一个引用。我看不出普通引用不起作用的原因。static\u cast
为您提供了该引用。@SamVarshavchik哦,对不起,我刚刚重新阅读了注释。你说的对。你说的是lambda参数。我看错了注释。谢谢你指出它。你好,coul你能纠正我在详细阐述上述方法时的错误吗?你基本上运行一个运行(或准备运行?)的lambda fnt.update()
。然后是“this”指向lambda函数?lambda的实际执行发生在数组启动期间?@nass我想我不理解这个问题。无论如何,想法是将lambda作为参数传递,让执行器使用正确的类型调用该函数,这样您就不必关心这些类型的数量和类型是的。折叠表达式还没有加入到游戏中。无论如何+1感谢你提到了它们。这在-std=c++11
的g++
上似乎没有运行,我还不能使用更新的标准。@nass是的,它确实需要-std=c++1z
和gcc,至少在6版中。实际上这很漂亮:)不错,但我会使用std::array
因为大小是已知的,它不需要分配任何东西:std::array&&
无论如何,请注意下面的内容。这个版本使用lambda,是使用函子的C++11,并且是这个答案中的版本。看看生成的代码。你注意到了什么?这个版本,即使经过优化,也要昂贵得多。非常有趣确实是我们,但值得一提。;-@W.F.如果你在godbolt上尝试它们,你会发现生成的代码几乎与使用lambdas或functor(当然,一旦优化)一样。事实上非常难以置信。是的。我错过了优化:)我想知道为什么数组版本如此庞大…lambdas的另一个专业人士:)嗨,我们能看看你的解决方案吗?Method
到底在那里做什么?我怎么解释它呢?我有点困惑:)当然Method
是一种承载关于单个成员函数的信息…它不存储任何信息,这与中的标记非常相似,但是解决方案不是标记分派,因为它不会通过参数将编译时信息传递给函数(runAll
),但通过模板参数…方法
执行有关SensorType
的信息以及指向成员函数的指针。这可以通过除普通旧类型之外的模板来执行,因为模板可以保存满足要求的非类型参数(它们通常需要静态访问)通过Method…
我们以双重方式解包SensorType
包-我们选择SensorType
本身,让Method
知道成员函数属于谁,然后我们将指针传递给方法…如果我们可以使用c++17,我们就不必像在那里使用的那样将传感器类型传递给方法...
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...});
}
};
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>...>();
}
};
#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(); });
}
};
#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();
}