如何正确使用invoke_result_t?
How to correctly use invoke_result_t?
我有一个我不理解的类型特征问题,我创建了下面的最小示例。为什么第二次调用 foo
不编译?它给出了错误:
from C:/msys64/mingw64/include/c++/10.3.0/bits/nested_exception.h:40,
from C:/msys64/mingw64/include/c++/10.3.0/exception:148,
from C:/msys64/mingw64/include/c++/10.3.0/ios:39,
from C:/msys64/mingw64/include/c++/10.3.0/ostream:38,
from C:/msys64/mingw64/include/c++/10.3.0/iostream:39,
from invoke_result_test.cpp:1:
C:/msys64/mingw64/include/c++/10.3.0/type_traits: In substitution of 'template<class _Fn, class ... _Args> using invoke_result_t = typename std::invoke_result::type [with _Fn = main()::<lambda(bool&)>; _Args = {bool}]':
invoke_result_test.cpp:6:11: required from here
C:/msys64/mingw64/include/c++/10.3.0/type_traits:2957:11: error: no type named 'type' in 'struct std::invoke_result<main()::<lambda(bool&)>, bool>'
2957 | using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
阅读它看起来该函数不可调用,因此 invoke_result 没有 type
到 return。我希望能够使用引用调用 foo,这样我就可以 return 值和非引用,但无法解决这个问题。这可能吗?我假设是这样,因为 STL 代码对此进行了管理。我有什么不明白的?
最小代码:
#include <type_traits>
template <typename F,
typename... A,
typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>
R foo(const F& aF, const A& ...aA)
{
return aF(aA...);
}
int main()
{
bool positive = true;
std::cout << foo([](bool flag) -> int
{
if (flag) return 1;
return -1;
},
positive);
std::cout << foo([](bool& flag) -> int
{
flag = !flag;
if (flag) return 1;
return -1;
},
positive);
}
谢谢。
错误表明无法使用给定参数调用该函数。
std::invoke_result
自动将 &&
添加到参数类型,除非它们已经有 &
。您的函数无法使用 bool &&
参数调用。
即使忽略 invoke_result
,这也行不通,因为 foo
通过 const 引用接收参数。
您需要完美转发此类包装器:
template <typename F, typename... A>
decltype(auto) foo(F &&f, A &&... a)
{
return std::forward<F>(f)(std::forward<A>(a)...);
}
这里可以手动指定return类型为std::invoke_result_t<F, A...>
.
但是为了保持一致性,您还应该将手动 f
调用替换为 std::invoke
(以支持调用成员指针之类的东西)。
template <typename F, typename... A>
std::invoke_result_t<F, A...> foo(F &&f, A &&... a)
{
return std::invoke(std::forward<F>(f), std::forward<A>(a)...);
}
template <typename F,
typename... A,
typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>
R foo(const F& aF, const A& ...aA)
这询问是否可以使用 A
右值调用 F
右值。
你不会尝试这个。您要尝试的是:
typename R = std::invoke_result_t<F const&, A const&...>>
如果您进行此更改,代码现在 properly fails to compile in the 2nd case,您可以在其中尝试使用 bool const&
参数调用 bool&
参数。
如果您希望第二种情况也有效,则不能通过 const&
获取 bool
,然后将其传递给需要 bool&
的 lambda。
template <typename F,
typename... A,
typename R = std::invoke_result_t<F const&, A&&...>>
R foo(const F& aF, A&& ...aA)
{
return aF(std::forward<A>(aA)...);
}
我有一个我不理解的类型特征问题,我创建了下面的最小示例。为什么第二次调用 foo
不编译?它给出了错误:
from C:/msys64/mingw64/include/c++/10.3.0/bits/nested_exception.h:40,
from C:/msys64/mingw64/include/c++/10.3.0/exception:148,
from C:/msys64/mingw64/include/c++/10.3.0/ios:39,
from C:/msys64/mingw64/include/c++/10.3.0/ostream:38,
from C:/msys64/mingw64/include/c++/10.3.0/iostream:39,
from invoke_result_test.cpp:1:
C:/msys64/mingw64/include/c++/10.3.0/type_traits: In substitution of 'template<class _Fn, class ... _Args> using invoke_result_t = typename std::invoke_result::type [with _Fn = main()::<lambda(bool&)>; _Args = {bool}]':
invoke_result_test.cpp:6:11: required from here
C:/msys64/mingw64/include/c++/10.3.0/type_traits:2957:11: error: no type named 'type' in 'struct std::invoke_result<main()::<lambda(bool&)>, bool>'
2957 | using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
阅读它看起来该函数不可调用,因此 invoke_result 没有 type
到 return。我希望能够使用引用调用 foo,这样我就可以 return 值和非引用,但无法解决这个问题。这可能吗?我假设是这样,因为 STL 代码对此进行了管理。我有什么不明白的?
最小代码:
#include <type_traits>
template <typename F,
typename... A,
typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>
R foo(const F& aF, const A& ...aA)
{
return aF(aA...);
}
int main()
{
bool positive = true;
std::cout << foo([](bool flag) -> int
{
if (flag) return 1;
return -1;
},
positive);
std::cout << foo([](bool& flag) -> int
{
flag = !flag;
if (flag) return 1;
return -1;
},
positive);
}
谢谢。
错误表明无法使用给定参数调用该函数。
std::invoke_result
自动将 &&
添加到参数类型,除非它们已经有 &
。您的函数无法使用 bool &&
参数调用。
即使忽略 invoke_result
,这也行不通,因为 foo
通过 const 引用接收参数。
您需要完美转发此类包装器:
template <typename F, typename... A>
decltype(auto) foo(F &&f, A &&... a)
{
return std::forward<F>(f)(std::forward<A>(a)...);
}
这里可以手动指定return类型为std::invoke_result_t<F, A...>
.
但是为了保持一致性,您还应该将手动 f
调用替换为 std::invoke
(以支持调用成员指针之类的东西)。
template <typename F, typename... A>
std::invoke_result_t<F, A...> foo(F &&f, A &&... a)
{
return std::invoke(std::forward<F>(f), std::forward<A>(a)...);
}
template <typename F,
typename... A,
typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>
R foo(const F& aF, const A& ...aA)
这询问是否可以使用 A
右值调用 F
右值。
你不会尝试这个。您要尝试的是:
typename R = std::invoke_result_t<F const&, A const&...>>
如果您进行此更改,代码现在 properly fails to compile in the 2nd case,您可以在其中尝试使用 bool const&
参数调用 bool&
参数。
如果您希望第二种情况也有效,则不能通过 const&
获取 bool
,然后将其传递给需要 bool&
的 lambda。
template <typename F,
typename... A,
typename R = std::invoke_result_t<F const&, A&&...>>
R foo(const F& aF, A&& ...aA)
{
return aF(std::forward<A>(aA)...);
}