是否可以建立一组模板化的函数指针,而无需手动进行操作呢? 这是一个例子,说明我在说什么。

假设我有一个经常被调用的函数“ write”,其中有两个实现(可以在它们之间进行动态切换)(write0和write1)。 这些写函数以参数类型为模板。 一种方法是仅使用内部使用if语句的模板化前端函数write()。

事实证明这足够快以满足我的需求,但是现在我想知道是否可以使用函数指针(只是为了好玩)来做同样的事情。 这种方法的问题是设置函数指针很麻烦。 除了本质上有条件(直接静态分派)之外,还有其他方法可以从根本上实现write()的理想吗?

(其他“规则”:我不能将Msg类更改为具有write()方法,也无法更改使用站点代码来用Msgs适配器替换Msgs。)

FWIW,我发现本文基本上说的是我在这里说的相同的话。

#include <iostream>
using namespace std;template<typename T> void write0(T msg) { cout << "write0: " << msg.name() << endl; }
template<typename T> void write1(T msg) { cout << "write1: " << msg.name() << endl; }// This isn't so bad, since it's just a conditional (which the processor will
// likely predict correctly most of the time).
bool use_write0;
template<typename T> void write(T msg) { if (use_write0) write0(msg); else write1(msg); }struct MsgA { const char *name() { return "MsgA"; } };
struct MsgB { const char *name() { return "MsgB"; } };
struct MsgC { const char *name() { return "MsgC"; } };
struct MsgD { const char *name() { return "MsgD"; } };// This doesn't work: templates may not be virtual.
#if 0
struct Writer { template<typename T> virtual void write(T msg) = 0; };
struct Writer0 { template<typename T> virtual void write(T msg) { cout << "write0: " << msg.name() << endl; } };
struct Writer1 { template<typename T> virtual void write(T msg) { cout << "write0: " << msg.name() << endl; } };
#endifint main(int argc, char **argv) {use_write0 = argc == 1;// I can do this:write(MsgA());// Can I achieve the following without the verbosity (manual setup, named// template instantiations, etc.)?void (*pwriteA)(MsgA) = use_write0 ? (void(*)(MsgA)) write0<MsgA> : (void(*)(MsgA)) write1<MsgA>;void (*pwriteB)(MsgB) = use_write0 ? (void(*)(MsgB)) write0<MsgB> : (void(*)(MsgB)) write1<MsgB>;void (*pwriteC)(MsgC) = use_write0 ? (void(*)(MsgC)) write0<MsgC> : (void(*)(MsgC)) write1<MsgC>;void (*pwriteD)(MsgD) = use_write0 ? (void(*)(MsgD)) write0<MsgD> : (void(*)(MsgD)) write1<MsgD>;pwriteA(MsgA());pwriteB(MsgB());pwriteC(MsgC());pwriteD(MsgD());return 0;
}

#1楼

如果您想在程序运行时来回切换日志记录功能,我认为您必须为每种类型手动设置功能指针。

如果仅在启动时选择日志记录功能就足够了,则可以完全通用的方式完成此操作,甚至无需知道以后将针对哪种类型调用该函数:

// writer functions
template<typename T> void write0(T msg) { std::cout << 0; };
template<typename T> void write1(T msg) { std::cout << 1; };// global flag
bool use_write0;// function pointers for all types
template<typename T>
struct dispatch {typedef void (*write_t)(T);static write_t ptr;
};// main write function
template<typename T>
inline void write(T msg) {(*dispatch<T>::ptr)(msg);
}// the fun part
template<typename T>
void autoinit(T msg) {if (use_write0)dispatch<T>::ptr = &write0<T>;elsedispatch<T>::ptr = &write1<T>;// call again for dispatch to correct functionwrite(msg);
}// initialization
template<typename T>
typename dispatch<T>::write_t dispatch<T>::ptr = &autoinit<T>;// usage example
int main(int argc, char **argv) {use_write0 = (argc == 1);write("abc");return 0;
}

对于每种类型T ,第一次调用write<T>()决定应使用哪种写入功能。 然后,以后的调用直接使用指向该函数的函数指针。


#2楼

您也可以使用Don Clugston的FastDelegates标头。 不会产生任何运行时开销,并且不会产生真正的面向对象的委托。 虽然使用它们的语法并不完美,但比摆弄原始函数指针要简单一些。


#3楼

为什么不使用函数指针数组?

#include <iostream>
using namespace std;template<typename T> void write0(T msg) { cout << "write0: " << msg.name() << endl; }
template<typename T> void write1(T msg) { cout << "write1: " << msg.name() << endl; }template<typename T> struct WriteSelector
{static void(* const s_functions[])(T msg);
};
template<typename T> void(* const WriteSelector<T>::s_functions[])(T msg)=
{&write0<T>,&write1<T>
};unsigned write_index=0;
template<typename T> void write(T msg)
{WriteSelector<T>::s_functions[write_index](msg);
}struct MsgA { const char *name() { return "MsgA"; } };
struct MsgB { const char *name() { return "MsgB"; } };
struct MsgC { const char *name() { return "MsgC"; } };
struct MsgD { const char *name() { return "MsgD"; } };void Test()
{write(MsgA());write(MsgB());write(MsgC());write(MsgD());
}int main()
{Test();write_index=1;Test();return 0;
}

#4楼

书写有两个变化轴:write0 / write1选择和MsgA / B / C ....选择。

从概念上讲,这意味着您需要NxM实现write功能。 当然,如果添加了写实现或消息类型,则会导致响应。 增加M或N个附加功能。

对于两个轴,您都可以选择使用静态或动态多态来实现它们。 静态多态性可以使用模板或使用函数替代来完成。

可以通过在每个类中创建具有N个写函数的N个元素类层次结构来完成。 但这将很快成为维护的噩梦。 除非消息内容也是运行时多态的。 但是问题是消息的静态多态性。

由于运行时多态性由于过于复杂而被排除在外(并且您不能拥有虚拟的模板函数,这会降低覆盖的冗长性),因此我们需要实现一个小的类型调度例程,将运行时信息转换为编译时信息。 。

更具体地说:用编写者使用的方法来对主要动作进行模板化(在示例中称为Tmain ),并使用来自“ real” main的正确模板参数来调用它。

这省略了“全局”选择变量的使用,但是是面向对象的和简洁的。

    // twodimensionalpolymorph.cpp//#include <iostream>using namespace std;class Write0 {public: template< typename tMsg > void operator()( /*const*/ tMsg& msg ) { cout << "write0: " << msg.name() << endl; };};class Write1 {public: template< typename tMsg > void operator()( /*const*/ tMsg& msg ) { cout << "write1: "<< msg.name() << endl; };};struct MsgA { const char *name() { return "MsgA"; } };struct MsgB { const char *name() { return "MsgB"; } };struct MsgC { const char *name() { return "MsgC"; } };struct MsgD { const char *name() { return "MsgD"; } };// the Tmain does the real action//template< typename Writer >int Tmain( Writer& write, int argc, char** args ) {write( MsgA() );write( MsgB() );write( MsgB() );write( MsgD() );return 0;}// the main merely chooses the writer to use//int main( int argc, char** args ) {if( argc==1 )return Tmain( Write0(), argc, args);elsereturn Tmain( Write1(), argc, args);}

还应该如何实现“模板化函数指针”?相关推荐

  1. c++模板之函数指针到函数对象:

    template<class R,class ARG> class pointer_to_unary_function<R,ARG> { R (*p)(ARG); public ...

  2. C++函数指针和模板

    一.函数指针声明 //函数原型 double sum(double,double); //函数指针的声明 double (*ptrSum)(double,double) 注意: 1,该语句声明了一个指 ...

  3. 网络编程之 信号捕捉器(函数指针与回调函数)

    接着我们的信号说下去      之前博主给大家分享到了信号的概念和初步介绍signal函数的形式后就没有继续往下介绍了,实在是因为时间不够,那个时候博主还要上课,现在博主放假了就好好给大家分享一下如何 ...

  4. C++ Primer 5th笔记(chap 16 模板和泛型编程)函数指针和实参推断

    1. 当用一个函数模板初始化一个函数指针或为一个函数指针赋值时, 编译器使用指针的类型来推断模板实参 template ctypename T> int compare (const T &am ...

  5. 面试官问你斐波那契数列的时候不要高兴得太早 搞懂C语言函数指针 搜索引擎还可以这么玩? 那些相见恨晚的搜索技巧...

    面试官问你斐波那契数列的时候不要高兴得太早 前言 假如面试官让你编写求斐波那契数列的代码时,是不是心中暗喜?不就是递归么,早就会了.如果真这么想,那就危险了. 递归求斐波那契数列 递归,在数学与计算机 ...

  6. 用模板函数与函数指针完成行为参数化

    用模板函数与函数指针完成行为参数化 函数模板:参数类型.返回值类型不具体指定,用一个虚拟的类型代表,主要特点是通用性强. 函数指针:指向函数的指针. 行为参数化:功能函数作为参数,实现不同的功能只需要 ...

  7. 二叉树(类模板、函数模板、函数对象、函数指针)

    这个二叉树的代码只是简单的实现了一些功能,比如插入和遍历.关键是用到了函数指针和函数对象,还有shared_ptr. 其中shared_ptr一定定义在节点中,因为new出来的空间时节点,释放的时候是 ...

  8. 《C和指针》—— 第13章 函数指针的作用1:回调函数2(与模板结合,简化代码)

    注意:此为原创文章,未经同意,请勿随意转载. 目录 1. 问题与思路 2. 具体实现 3. 结果截图 1. 问题与思路 Q:实现一个与类型无关的比较函数,且考虑模板,精简代码 A:声明一个函数指针,函 ...

  9. boost源码剖析之:泛型函数指针类boost::function(rev#3)

    boost源码剖析之:泛型函数指针类boost::function(rev#3) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba)   Note: 并非新作,03年曾放 ...

最新文章

  1. 解决运行eclipse内存不足的问题
  2. IOS设计模式学习(1)设计模式初窥
  3. 一个操作系统的实现第九章笔记
  4. 2020 年最全 Python 面试题汇总 (五)
  5. RHCE-samba服务
  6. JS实现滚动监听以及滑动到顶部
  7. 封装EF code first用存储过程的分页方法
  8. Go单元测试--模拟服务请求和接口返回
  9. 【机器学习】监督学习--(回归)岭回归
  10. openwrt里面的高深代码-两行shell脚本
  11. 软件度量都该度个啥?
  12. 推荐一个国外的关于奥运报道的网站.
  13. vb6实现下载带进度
  14. Invest模型 ——生境质量计算
  15. c语言环比,同比、环比的区别及计算公式
  16. 人望山 鱼窥荷下一句_一窥R反文化
  17. 日语开发java自我介绍,用日语自我介绍,这些你一定会用到
  18. 基于WPF的科学计算器程序
  19. android模拟器不玩游戏,安卓模拟器哪个玩游戏最流畅?
  20. 阿里双11集团技术总指挥——汤兴:一场不亚于移动化的变革已经发生

热门文章

  1. 回溯算法-----复原IP地址(Java版本)
  2. 人生必做清单-----持续更新
  3. tools.jar seem to ....
  4. 如何在BIOS里设置定时关机?
  5. html 失效,如何让css失效?
  6. Kafka Cluster元数据在客户端缓存采用的数据结构
  7. jieba(结巴)常用方法
  8. Remove Nth Node From End of List - LeetCode
  9. sublime 写lua相关的插件 cocos
  10. 有关Nodejs的一些插件介绍