提问人:Jarod42 提问时间:11/26/2022 最后编辑:Jarod42 更新时间:11/27/2022 访问量:350
检测已删除的功能
Detect deleted function
问:
有没有办法在重载选择后检测已删除的函数(在没有可行或不明确的重载上)?
void foo();
void foo(double) = delete;
void foo(std::string);
void foo(char, int);
void foo(int, char);
static_assert(!foo_is_deleted<>); // exist as not deleted
static_assert( foo_is_deleted<double>); // explicitly deleted
static_assert( foo_is_deleted<float>); // foo(4.2f) selects foo(double) which is deleted.
static_assert(!foo_is_deleted<const char*>); // foo("..") selects foo(std::string) which is not deleted.
static_assert(!foo_is_deleted<std::vector<int>>); // No viable overload, so not deleted
static_assert(!foo_is_deleted<char, char>); // ambiguous overload, so not deleted
答:
以下内容不正确,因为它无法区分不明确的重载解决方案和已删除的重载结果。我想不出一种方法来区分它。
我将把我之前的答案留在下面供参考。
也许是这样的(https://godbolt.org/z/hTsq5rYnq):
namespace foo_is_deleted_impl {
template<typename...>
void foo(...);
}
template<typename... Args>
inline constexpr auto foo_is_deleted = []{
auto a = requires { foo(std::declval<Args>()...); };
using namespace foo_is_deleted_impl;
auto b = requires { foo(std::declval<Args>()...); };
return !(a || b);
}();
这个想法是首先测试重载解决是否成功,并具有可用的候选者(意味着未删除)。a
然后,我使重载对 lambda 中的非限定名称查找可见,并重复测试。重载的声明方式使我认为它不可能比任何其他重载都更适合(如果有人发现我遗漏的案例,请告诉我)。foo_is_deleted_impl::foo
using namespace
b
如果为 true,则肯定没有进行已删除的重载,所以我返回 .a
false
如果不是 true,而是 是,则 的重载解析必须失败,因为为 选择的重载不会比为 选择的重载更好,因此再次返回。a
b
a
b
a
false
如果 和 都为 false,则有两种可能性:要么失败,因为选择了其中一个非重载并被删除,在这种情况下我返回,要么它失败,因为重载解析变得不明确。然而,这意味着 的重载解决确实找到了可行的候选者,因此应返回其结果。a
b
b
foo_is_deleted_impl::foo
true
foo_is_deleted_impl::foo
a
对于所有这些,重要的是在范围方面彼此相对,并按原样放置。在声明下方的位置也很重要,因为只有 ADL 会从实例化点进行查找。foo
foo_is_deleted_impl
foo_is_deleted
foo_is_deleted
foo
这也假定这是使用非限定名称调用的自由函数(模板)的重载集。它应该适用于 ADL。foo
评论
std::is_invocable
吗?foo(std::vector<int>{})
is_deleted
,也许您可以搜索有关它的信息。