推导模板化函数中的函数重载

时间:2018-10-02 21:17:08

标签: c++ c++11

我正在编写自己的std :: async模拟(必须回溯至Intel13 / gcc 4.4 STL),并且工作正常:

template <typename Func, typename ...Args>
struct return_value {
    template <typename T>
    using decayed = typename std::decay<T>::type;
    using type    = typename std::result_of<decayed<Func>(decayed<Args>...)>::type;
};

template <typename Func, typename ...Args>
typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
    return func(args...);
}

void run(int a, double b) { 
    printf("a: %i  b: %f\n", a, b);
}

int main() {
    async(run, 1, 3.14);
}

但是,如果我为run添加了重载:

void run() {
    printf("no args\n");
}

然后它无法正确解决:

<source>: In function 'int main()':
<source>:27:23: error: no matching function for call to 'async(<unresolved overloaded function type>, int, double)'
     async(run, 1, 3.14);
                       ^
<source>:14:43: note: candidate: 'template<class Func, class ... Args> typename return_value<Func, Args>::type async(Func&&, Args&& ...)'
 typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
                                           ^~~~~
<source>:14:43: note:   template argument deduction/substitution failed:
<source>:27:23: note:   couldn't deduce template parameter 'Func'
     async(run, 1, 3.14);
                       ^
Compiler returned: 1

如何将函数用作模板参数并正确推断给定参数的重载?

1 个答案:

答案 0 :(得分:0)

除非您知道返回类型,否则我个人看不出消除过载歧义的方法。您可以假设最常见的返回类型为void,然后这样做:(为简便起见,我正在简化您的示例)

template <class F, class... Args>
auto async(F f, Args... args)
{
    return f(args...);
}

template <class... Args>
auto async(void (*f)(Args...), Args... args)
{
    return f(args...);
}

void run();
void run(int, double);

auto test()
{
    async(run); // calls run();
    async(run, 1, 2.); // calls run(int, double);
}

这似乎给用户带来了麻烦和困惑。为什么当传递的函数返回void而返回int却不起作用时,它为什么起作用?所以我不推荐。

所以实际上,您唯一能做的就是让它掌握在用户手中。

为您的函数调用者提供一些解决方案:

好的(丑陋的)旧方法:使用强制转换消除过载:

async(static_cast<int(*)(int, double)>(run), 1, 2.);

我个人根本不喜欢这种方法。我不喜欢它的冗长,而且最不喜欢的是,我必须对应该真正隐含的东西保持明确。

lambda方式

async([] { return run(1, 2.); });

我喜欢这个。还不错。仍然有些冗长,但是比其他方法更好。

宏方式

是的,宏,在C ++中。事不宜迟,就存在了(为简便起见,省略了完美的转发):

#define OVERLOAD(foo) [] (auto... args) { return foo(args...); }
async(OVERLOAD(run), 1, 2.);

我不会对此发表评论。我让你们每个人都来判断这个宏。

相关问题