使用函数时避免使用指定模板参数

Avoid to specity template argument when using a function

提问人:Jepessen 提问时间:10/5/2023 更新时间:10/6/2023 访问量:88

问:

我想编写一个将 a 作为参数的模板函数,如下所示:std::function

 template<typename T>
 void registerDelegate(std::function<void(const T&)> d) {
   d(T{});
 }

当我想使用它时,我需要以明确的方式编写模板参数:T

 auto d = [](const std::string& message) { int i = 0; };
 registerDelegate<std::string>(d);

这很烦人,因为我已经在 lambda 中定义了它。有没有办法避免它,简单地写:

registerDelegate(d);

当我想使用该功能时,同时始终知道 T 是什么?

C++ 模板 template-argument-deduction

评论

0赞 Sam Varshavchik 10/5/2023
我会尝试在这里制作一个用户定义的演绎指南,对于非捕获 lambda 来说应该相当容易。也许能够让它为捕获工作,需要一些汗水和泪水。这需要深入的黑客攻击来调查。
1赞 chrysante 10/5/2023
你可以写 or .编译器在尝试为 选择参数化时不考虑隐式转换,因为它不能。每个专业化都可以专门用于支持各种疯狂的转换,而编译器不可能尝试所有转换。因此,您可以告诉编译器使用哪一个,方法是使用 as 参数或显式指定 .registerDelegate(std::function(d));std::function d = [](std::string) {...}; registerDelegate(d);registerDelegatestd::function<...>std::function<void(std::string)>T

答:

2赞 YSC 10/5/2023 #1

您可以利用 的扣除指南:std::function

template<class Functor>
void registerDelegate(Functor&& functor)
{
   std::function f = functor;
   (void) f;
}

如果需要访问参数类型:

template<class Functor>
auto to_function(Functor&& functor)
{
    std::function f = functor;
    return f;
}
 
template<class Arg>
void registerDelegate(std::function<void(const Arg&)> d) {
    d(Arg{});
}

auto d = [](std::string const&){};
registerDelegate(to_function(d));
1赞 Jan Schultke 10/5/2023 #2

问题在于,在模板参数推导过程中不考虑隐式转换。如果你想推导出 ,你需要一个 ,而不仅仅是可转换为 的东西。TregisterDelegatestd::functionstd::function

在 C++17 中,这可以通过使用类模板参数推导和 std::function 推导指南轻松解决。

auto d = [](std::string const&){};
registerDelegate(std::function{d});

请参阅 Compiler Explorer 中的实时示例

3赞 Ted Lyngmo 10/5/2023 #3

您可以将提供给的任何函子转发给 lambda(或函数模板),以 a 来推断。registerDelegatestd::function<void(const T&>T

template <class F>
void registerDelegate(F&& d) {
    []<class T>(std::function<void(const T&)> del) {
        del(T{});
    }(std::function(std::forward<F>(d))); // use std::function's deduction guides
}

您可以为尚未包装在 中的函子/函数添加函数模板,而不是更改当前已匹配的函数模板:std::function<void(const T&)>std::function

template<class F>
decltype(auto) registerDelegate(F&& func) {
    // call your already existing function:
    return registerDelegate(std::function(std::forward<F>(func)));
    //                           ^ use std::function's deduction guides
}

评论

0赞 Jepessen 10/5/2023
如果我有自己的委托 (codeproject.com/Articles/1170503/...) 而不是 ,该怎么办?std::function
0赞 Ted Lyngmo 10/5/2023
@Jepessen 这是一篇相当宽松的文章。:)你的意思是你的函数仍然需要一个,但你希望它与无法推断类型的东西相匹配吗?std::function<void(const T&)>std::function
0赞 Jepessen 10/6/2023
基本上是的。我们正在使用受我之前评论中链接的文章启发的自定义委托,因为它通常比 .因此,我们在代码中使用此类而不是 std::function。我在示例中使用它只是为了了解我需要什么,但现在我认为我必须编写我的委托演绎指南......std::function
1赞 Ted Lyngmo 10/6/2023
@Jepessen我明白了。是的,要使相同的解决方案适用于非类型,它需要类似的演绎指南。另一个说明:正如我在答案中暗示的那样,您也可以将函数转发到您现有的函数模板。我把它添加到答案中,以使其更清楚。std::functionFstd::function<void(const T&>