【问题标题】:Dealing with <unresolved overloaded function type> when passing function pointer to function将函数指针传递给函数时处理<未解析的重载函数类型>
【发布时间】: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&lt;int(int)&gt;。这样返回类型和参数的表达就更清楚了。
  • #define OVERLOAD_SET(f) [](auto&amp;&amp;... args) -&gt; decltype(f(static_cast&lt;decltype(args)&gt;(args)...)) { return f(static_cast&lt;decltype(args)&gt;(args)...);} 然后c(OVERLOAD_SET(goo), 10)
  • 逻辑上等同于静态转换方法,但我认为这看起来更干净:void (*goo_ptr)()=goo; c(goo_ptr);
  • @cpplearner 很酷,它有效,感谢您的回答。不过,我不是宏的忠实粉丝。
  • 我对现代编译器完全优化掉多余变量的能力非常有信心。

标签: c++ c++11


【解决方案1】:

我的意思是,你总是可以明确指定模板参数:

c<int(int)>(&goo, 10);
c<void()>(&goo);

AFAIK 在c 中无法做到这一点,因为无法推断出F(重载之间的歧义),并且要使编译器推断出正确的类型,您需要在调用方进行更改。

【讨论】:

    【解决方案2】:

    如果 C++14 可用,那么泛型 lambda 可以解决“将重载集作为函数参数传递”问题:

    #define FWD(arg) static_cast<decltype(arg)&&>(arg)
    auto goo_fn = [](auto&&... args) -> decltype(goo(FWD(args)...)) {
        return goo(FWD(args)...);
    };
    
    c(goo_fn, 10); // ok
    c(goo_fn);     // ok
    

    goo_fn 是一个 lambda,它透明地(尽可能多地)表示 goo 的重载集。尾随 decltype 是必要的,原因有两个:(1)如果 goo 的重载是,则确保返回类型是引用;(2)确保 SFINAE 友好(decltype(auto) 不会。

    【讨论】:

    • 这是一个相当冗长的解决方案,我正在研究 pairproposals 以将其减少到仅 [](args...) =&gt; goo(&gt;&gt;args...)。猜猜我们会看到。
    • 史诗。顺便说一句,FWD == std::forward(args)...
    • @JayYang 我定义它的方式编译速度会更快,否则行为相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-01
    • 1970-01-01
    相关资源
    最近更新 更多