【发布时间】:2017-09-04 23:43:32
【问题描述】:
让我们考虑一下:
void goo () {
std::cout << "void goo ()\n";
}
int goo (int) {
std::cout << "int goo (int)\n";
return 42;
}
现在我想使用如下定义的一些包装函数调用其中一个函数:
template <typename F, typename... A>
void c (F&& f, A&&... a) {
f (std::forward<A> (a)...);
}
有用法:
c (&goo, 10); // (X)
c (&goo); // (Y)
两种情况都失败 (GCC 5.3.1) 并出现相应错误:
error: no matching function for call to ‘c(<unresolved overloaded function type>, int)’
error: no matching function for call to ‘c(<unresolved overloaded function type>)’
就我而言,失败是因为编译器在必须初始化 f 对象时无法选择适当的重载(信息太少)。
作为一种解决方案,我当然可以像这样编写用法调用:
c (static_cast<int (*) (int)> (&goo), 10);
c (static_cast<void (*) ()> (&goo));
告诉编译器我真正想使用哪个指针。
为我写这个static_cast 会使代码更难看,所以我写了一个包装函数,用于使用模板将函数指针转换为适当的指针:
template <typename R, typename... Args>
using Funptr_t = R (*) (Args...);
template <typename R, typename... Args>
Funptr_t<R, Args...> funptr (Funptr_t<R, Args...> ptr) {
return static_cast<Funptr_t<R, Args...>> (ptr);
}
现在使用看起来好多了:
c (funptr<int, int> (&goo), 10);
c (funptr<void> (&goo));
我的问题是:您对如何处理这种情况有更好的想法吗?我很确定这在通用代码中经常发生。所以,请给我一些建议。
如果我可以直接使用 (X) 和 (Y),理想的解决方案是使用 A... 来完成指向适当重载的魔术并将其隐藏给调用者。
【问题讨论】:
-
我会坚持选角。它可能很难看,但至少任何 C++ 程序员都能理解正在做什么。您的方式将要求他们查找
funptr。如果你坚持,至少要让funptr处理 function type 模板参数。 IE。funptr<int(int)>。这样返回类型和参数的表达就更清楚了。 -
#define OVERLOAD_SET(f) [](auto&&... args) -> decltype(f(static_cast<decltype(args)>(args)...)) { return f(static_cast<decltype(args)>(args)...);}然后c(OVERLOAD_SET(goo), 10) -
逻辑上等同于静态转换方法,但我认为这看起来更干净:
void (*goo_ptr)()=goo; c(goo_ptr); -
@cpplearner 很酷,它有效,感谢您的回答。不过,我不是宏的忠实粉丝。
-
我对现代编译器完全优化掉多余变量的能力非常有信心。