c++ - 还有什么办法可以实现 "templated function pointers"?

标签 c++ templates function-pointers

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

假设我有一个经常调用的函数“write”,我有两个实现(write0 和 write1),我希望能够在它们之间动态切换。这些写入函数是根据参数类型进行模板化的。实现此目的的一种方法是仅使用一个模板化前端函数 write(),它在内部使用 if 语句。

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

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

FWIW,我发现this article基本上我在这里说的是同样的事情。

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

int 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;
}

最佳答案

如果你想在程序运行时来回切换日志函数,我认为你必须手动设置每种类型的函数指针。

如果在启动时选择日志函数就足够了,那么它可以以完全通用的方式完成,甚至不需要知道稍后将调用该函数的类型:

// 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>;
   else
      dispatch<T>::ptr = &write1<T>;
   // call again for dispatch to correct function
   write(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>()决定应使用哪个写入功能。稍后的调用则直接使用指向该函数的函数指针。

关于c++ - 还有什么办法可以实现 "templated function pointers"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/560322/

相关文章:

C++ 运行时,显示异常消息

c++ - C++中整数如何相乘?

c++ - USB2Serial 的 Linux IOCTL

c++ - 指向构造函数重载的指针?

c++ - ADL的陷阱是什么?

c++ - 模板默认参数丢失其引用类型

c++ - 如何根据其他参数设置嵌套模板类实例化作为默认模板参数

c++ - 在这种情况下应该使用 C++ 模板吗?

C++ std::map 异构函数指针

c++ - 如何理解使用 typedef 定义函数指针?