【发布时间】:2020-04-02 14:19:43
【问题描述】:
我想要两个函数:接受void(*)(int) 和int(*)(int)。
如何编写类似于 std::is_invocable_r 的 type_trait 但检查确切的返回类型(因为任何函数都可以转换为返回 void 的函数)。
#include <functional>
#include <type_traits>
#include <cstdio>
template <typename R, typename C, typename... Args>
constexpr bool is_exact_invocable_r_v =
std::is_same_v<R, std::invoke_result_t<C, Args...>>;
// std::is_invocable_r_v<R, C, Args...>;
template<typename C, std::enable_if_t<is_exact_invocable_r_v<int, C>, int> = 0>
void print(C)
{
printf("1\n");
}
template<typename C, std::enable_if_t<is_exact_invocable_r_v<int, C, int>, int> = 0>
void print(C)
{
printf("2\n");
}
template<typename C, std::enable_if_t<is_exact_invocable_r_v<void, C, int>, int> = 0>
void print(C)
{
printf("3\n");
}
int main()
{
print([](){return 0;});
print([](int){return 0;});
print([](int){});
}
std::is_invocable_r_v<R, C, Args...> 会导致歧义,因为任何类型都可以强制转换为 void。
std::is_same_v<R, std::invoke_result_t<C, Args...>> 导致替换失败。
【问题讨论】:
-
澄清一下:
short(*)(int)不应该匹配任何重载? IOW,std::is_same_v<decltype(C(0)), int>? -
另外,
std::is_same_v不是 C++11 的一部分 -
请编辑以添加您从该程序获得的确切错误消息。
-
这与将结果强制转换为 void 无关。问题是您正在混合“这是调用我的可调用对象的有效方法”和“返回类型是什么”的步骤。第一步是 SFINAE 友好的,第二步不是。仅当
is_invokable不产生替换失败时,您才需要有条件地检查invoke_result。 -
或者换一种说法,SFINAE 可以消除导致使用不同特化或重载的声明,但您只有一个模板声明,如果
invoke_result_t是非法的。