【发布时间】:2020-08-10 12:10:03
【问题描述】:
这不适用于 gcc-10 或 clang-10。
template <typename R, typename T>
auto invoke_function(R (&f)(T), T t) { return std::invoke(f, t); }
invoke_function(std::to_string, 42);
这适用于 gcc-10,但不适用于 clang-10。
template <typename R, typename T>
auto invoke_function(T t, R (&f)(T)) { return std::invoke(f, t); }
invoke_function(42, std::to_string);
错误消息在所有情况下都非常相似:“无法推断模板参数'R'”或“无法推断模板参数'R'”(gcc)。
目前尚不清楚此代码被拒绝的原因。由于推导出T,可以确定std::to_string的过载。对参数顺序的依赖特别烦人。它不应该工作吗?
我知道这个问题可以通过引入一个函数对象来回避:
struct to_string
{
template<typename T> std::string operator()(T t) { return std::to_string(t); }
};
然后只使用std::invoke 就可以了。然而,这需要为每个重载集创建一个单独的函数对象。
有没有更好的办法?
【问题讨论】:
-
不,你不能:Can I take the address of a function defined in standard library?。可能是骗子!顺便说一句,我们不能有一个通用的 lambda 而不是你提供的仿函数!不会少打字吗?
-
@JeJo 这似乎不太相关。 if we use our own overload set 存在同样的推导问题,而不能形成对标准函数的引用这一事实只是额外的破坏层。
-
IIRC,编译器应该尝试将模板参数与每个函数参数分开推导,并且只有当多个参数共享一个类型时它们匹配时才能推导成功。我很惊讶 GCC 从第二个版本开始工作。你真的需要
R和T吗?有多种方法可以获取函数的返回类型,例如using return_type = decltype(f(t));,您可以使用 SFINAE 检查函数是否可以使用t调用,或者使用静态资源来获取很好的错误消息。 -
@NathanOliver "有多种方法可以获取函数的返回类型" 确实,但是在获取单个函数之前,我们需要解决一个重载集。你是怎样做的?请注意,每个名为
std::to_string的函数 都可以使用int参数调用。 -
@JeJo 好点。一个通用的 lambda 确实是一种改进。
标签: c++ c++17 language-lawyer template-argument-deduction