如何在重载选择后检测被删除函数(排除无可行/歧义重载)
检测重载决议后选中被删除函数的方法
要实现你需要的foo_is_deleted trait,我们可以通过两层SFINAE分别检测是否存在可行重载和选中的重载是否可调用,两者结合即可区分目标场景:
#include <type_traits> #include <utility> #include <string> #include <vector> // 原函数重载 void foo(); void foo(double) = delete; void foo(std::string); void foo(char, int); void foo(int, char); // 检测是否存在可行重载(重载决议能选出唯一函数,无论是否被删除) template <typename... Args, typename = void> struct has_viable_overload : std::false_type {}; template <typename... Args> struct has_viable_overload<Args..., std::void_t<decltype(foo(std::declval<Args>()...))>> : std::true_type {}; // 检测选中的重载是否可调用(即未被删除) template <typename... Args, typename = void> struct is_callable : std::false_type {}; template <typename... Args> struct is_callable<Args..., std::void_t<decltype((foo(std::declval<Args>()...)))>> : std::true_type {}; // 最终trait:存在可行重载且选中的是被删除的函数 template <typename... Args> struct foo_is_deleted : std::bool_constant<has_viable_overload<Args...>::value && !is_callable<Args...>::value> {}; template <typename... Args> constexpr bool foo_is_deleted_v = foo_is_deleted<Args...>::value; // 测试用例 static_assert(!foo_is_deleted_v<>); // 存在且未被删除 static_assert( foo_is_deleted_v<double>); // 显式删除 static_assert( foo_is_deleted_v<float>); // float隐式转换到double,选中被删除的重载 static_assert(!foo_is_deleted_v<const char*>); // const char*隐式转换到std::string,选中未被删除的重载 static_assert(!foo_is_deleted_v<std::vector<int>>); // 无可行重载,返回false static_assert(!foo_is_deleted_v<char, char>); // 歧义重载,返回false
原理说明
has_viable_overload:- 利用
std::void_t检测decltype(foo(std::declval<Args>()...))是否合法:- 如果重载决议能选出唯一函数(无论是否被删除),函数返回类型确定,
decltype表达式合法,trait返回true; - 如果无可行重载或存在歧义,重载决议失败,
decltype表达式非法,trait返回false。
- 如果重载决议能选出唯一函数(无论是否被删除),函数返回类型确定,
- 利用
is_callable:- 同样利用
std::void_t,直接检测调用表达式foo(std::declval<Args>()...)是否合法:- 若选中的重载未被删除,调用合法,trait返回
true; - 若选中的重载被删除,调用触发编译错误(SFINAE语境下视为替换失败),trait返回
false; - 无可行重载或歧义时,同样返回
false。
- 若选中的重载未被删除,调用合法,trait返回
- 同样利用
foo_is_deleted:- 结合前两个trait:当存在可行重载且选中的重载不可调用时,说明选中了被删除的函数,返回
true;其他情况均返回false。
- 结合前两个trait:当存在可行重载且选中的重载不可调用时,说明选中了被删除的函数,返回
内容的提问来源于stack exchange,提问作者Jarod42
相关产品推荐
相关产品推荐

