检测已删除的功能

Detect deleted function

提问人:Jarod42 提问时间:11/26/2022 最后编辑:Jarod42 更新时间:11/27/2022 访问量:350

问:

有没有办法在重载选择后检测已删除的函数(在没有可行或不明确的重载上)?

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
C++ 类型特征 deleted-functions

评论

0赞 Nelfeal 11/26/2022
这不是std::is_invocable吗?
0赞 Jarod42 11/26/2022
@Nelfeal:不可调用,但不会删除。foo(std::vector<int>{})
0赞 Bob__ 11/26/2022
反射 TS 中列出了一个is_deleted,也许您可以搜索有关它的信息。
1赞 Nelfeal 11/26/2022
我认为这是不可能的,因为“构造指向已删除函数的指针,甚至在未计算的表达式中使用已删除的函数”格式不正确。你甚至不能使用这样的技巧来检查函数是否被声明,因为删除的函数会被选中。你需要对此进行反思。
4赞 Jeff Garrett 11/26/2022
出于好奇,如何使用它?

答:

3赞 user17732522 11/26/2022 #1

以下内容不正确,因为它无法区分不明确的重载解决方案和已删除的重载结果。我想不出一种方法来区分它。

我将把我之前的答案留在下面供参考。


也许是这样的(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::foousing namespaceb

如果为 true,则肯定没有进行已删除的重载,所以我返回 .afalse

如果不是 true,而是 是,则 的重载解析必须失败,因为为 选择的重载不会比为 选择的重载更好,因此再次返回。ababafalse

如果 和 都为 false,则有两种可能性:要么失败,因为选择了其中一个非重载并被删除,在这种情况下我返回,要么它失败,因为重载解析变得不明确。然而,这意味着 的重载解决确实找到了可行的候选者,因此应返回其结果。abbfoo_is_deleted_impl::footruefoo_is_deleted_impl::fooa

对于所有这些,重要的是在范围方面彼此相对,并按原样放置。在声明下方的位置也很重要,因为只有 ADL 会从实例化点进行查找。foofoo_is_deleted_implfoo_is_deletedfoo_is_deletedfoo

这也假定这是使用非限定名称调用的自由函数(模板)的重载集。它应该适用于 ADL。foo

评论

0赞 Jarod42 11/26/2022
通过演示进行模棱两可的调用失败:/
0赞 user17732522 11/27/2022
@Jarod42哦,对了。我忘了考虑这一点。不确定该部分是否可以解决。
0赞 habrewning 11/27/2022
这个练习的目的是什么?foo_is_deleted确定的信息在调用之前是静态已知的。为什么要在运行时执行它?
0赞 user17732522 11/27/2022
@habrewning 在我的回答中,运行时没有执行任何内容。这只是对语言当前提供的内容进行反思的尝试。希望我们能在某个时候得到适当的反思。
0赞 habrewning 11/27/2022
啊,好吧。我错了。你应该在你的回答中说出来。因为构造 []{ ... }();不是很好理解。对于大多数人来说,这样的计算可以在编译时完成会令人惊讶。此标准是否符合,或者编译器是否只是宽容。在 en.cppreference.com/w/cpp/language/constant_expression 上有 37 条关于常量表达式的规则。您的解决方案是其中之一吗?只是想知道。