c++ - 无法推断函数返回类型

标签 c++ c++17 language-lawyer template-argument-deduction

这不适用于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。但是,这需要为每个重载集创建一个单独的函数对象。
有没有更好的办法?

最佳答案

It isn't clear why this code is rejected. Since T is deduced, the overload of std::to_string can be determined.


那不是完全正确的方式。模板推导首先独立推导每个参数/参数对-然后我们将所有推导放在一起,并确保它们是一致的。因此,我们从T推断出42,然后分别从R(&)(T)推断出std::to_string。但是std::to_string的每个重载都匹配该模式,因此我们不知道选择哪个模式。
但是,只有当我们能够独立推导每一对时,上述情况才成立。如果参数不可推导,我们将其跳过,然后尝试返回并稍后再填写。这就是这里的关键-我们重新构造推论,以便仅从T推导42:
template <typename T>
auto invoke_function(std::string (&f)(std::type_identity_t<T>), T t) { return std::invoke(f, t); }
在这里,我们推导Tint,现在我们从std::string(&)(int)推导std::to_string。现在有效,因为只有单个重载会匹配该模式。

除了现在,这是未定义的行为,按照[namespace.std]/6:

Let F denote a standard library function ([global.functions]), a standard library static member function, or an instantiation of a standard library function template. Unless F is designated an addressable function, the behavior of a C++ program is unspecified (possibly ill-formed) if it explicitly or implicitly attempts to form a pointer to F.

std::to_string不是可寻址函数。
因此,真正更好的方法是将to_string包装在一个lambda中,然后传递它:
invoke_function([](auto x){ return std::to_string(x); }, 42);
只需调整invoke_function即可接受任意可调用对象,而不是专门使用一个函数。该lambda包装可以概括为:
#define FWD(x) static_cast<decltype(x)&&>(x)
#define LIFT(name) [&](auto&&... args) noexcept(noexcept(name(FWD(args)...))) -> decltype(name(FWD(args)...)) { return name(FWD(args)...); }

invoke_function(LIFT(std::to_string), 42);

关于c++ - 无法推断函数返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63339921/

相关文章:

堆栈上的 C++ 变量似乎没有在函数作用域的末尾被释放

c++ - gcc 中的默认构造内联静态随机数引擎

c++ - 在 NULL 指针上调用 delete - C++03 与 C++11

c++ - 为什么 llvm::Module 存储在 unique_ptr 中?

c++ - 是什么使得 volatile 破坏了结构的指针算术?

c++ - 如何为静态常量模板化专用整数值分配存储

c++ - 获取可执行文件的路径(使用 std::filesystem)

c++ - 在取地址的上下文中,哪个是最专业的函数模板?

c++ - 如果需要转换,我可以在将参数移动到另一个参数的同时读取参数吗?

C++ 两个类相互转换并调用它们的函数