【问题标题】:What are the types that are considered callables in C++?哪些类型在 C++ 中被视为可调用对象?
【发布时间】:2018-03-27 01:01:07
【问题描述】:

我试图了解可以作为 std::invoke 的第一个参数传递的事物的概念和类型的层次结构。

让我们考虑一个类型F,这样至少存在一个Args的组合,这样std::is_invokable_v<F, Args...>就是true

问题[1]:F可以是哪些类型?

这是一个暂定列表:

  • std::function_v<F> 等函数是true
  • 一个函数指针,使得std::function_v<std::remove_pointer_t<F>>true
  • 一个函数引用,使得std::function_v<std::remove_reference_t<F>>true
  • 对函数指针的引用,使得std::function_v<std::remove_pointer_t<std::remove_reference_t<F>>>true
  • 指向成员函数的指针,使得std::is_member_function_pointer_v<F>true
  • 对指向成员函数的指针的引用使得std::is_member_function_pointer_t<std::remove_reference_t<F>>true
  • 指向成员对象的指针,使得std::is_member_object_pointer_v<F>true
  • 对指向成员对象的指针的引用使得std::is_member_object_pointer_v<std::remove_reference_t<F>>true
  • 一个类使得std::is_class_v<F>true 并且这样F::operator() 存在
  • 对类的引用,使得std::is_class_v<std::remove_reference_t<F>>true 并且存在std::remove_reference_t<F>::operator()
  • 一个联合使得std::is_union_v<F>true 并且这样F::operator() 存在
  • 对联合的引用,使得std::is_union_v<std::remove_reference_t<F>>true,并且存在std::remove_reference_t<F>::operator()
  • 闭包类型
  • 对闭包类型的引用,使得std::remove_reference_t<F> 是闭包类型

这个列表正确吗?还有其他可行的选择吗?

问题 [2]: 闭包类型只是 lambda 表达式的类型,还是在 C++ 中有其他方法可以创建被视为闭包类型的东西?

问题 [3]: 标准有时会谈到函数对象:问题 1) 列表中的哪些内容被视为函数对象?

问题 [4]: 执行以下操作:

  • 闭包类型
  • 一个类使得std::is_class_v<F>true 并且这样F::operator() 存在
  • 一个联合使得std::is_union_v<F>true 并且这样F::operator() 存在

属于标准中的特定概念(基本上是具有operator() 的东西)?如果不是,那么用于检测类型是否满足所列项目符号之一的类型特征的好名称(例如,如果这样的事物在计算机科学或其他编程语言中具有通用名称)是什么?

【问题讨论】:

  • 我认为可调用对象只是“任何x 使得x(some arguments) 有效”
  • "闭包类型" 这是多余的,因为闭包类型根据定义是类类型。

标签: c++ lambda c++17 functor typetraits


【解决方案1】:
  1. R(Args...)R(Args...) noexceptR(Args......)R(Args......) noexcept 形式的函数类型。
  2. (可能是 cv 限定的)指向 #1 的指针。
  3. (可能是 cv 限定的)类类型,至少具有一个公共 operator() 成员(包括继承);
  4. (可能是 cv 限定的)类类型至少有一个公共非显式转换函数到 a) 引用 #1、b) #2 或 c) 引用 #2(包括继承);
  5. (可能是 cv 限定的)指向成员的指针。
  6. 参考上述内容。

对于#3、#4 及其引用,还有一个额外的限定,即类型中编码的 cv 限定和值类别必须与至少一个这样的函数兼容。

"Function object types" 是可以使用通常的函数调用语法(即#2-#4)调用的对象类型。指向成员的指针不符合条件,因为您不能使用 () 调用它们。

根据定义,"callable type" 是“函数对象类型或指向成员的指针”,即 #2-#5。

函数类型和引用类型不是对象类型,因此既不是函数对象类型也不是可调用类型,但可以通过std::decay的应用合二为一。

【讨论】:

  • 即使std::is_class_vfalse,联合是否也被视为类类型?
  • 是的。就核心语言而言,两者都是类类型。
  • 您能否在回答中澄清为什么 5 不是函数对象类型?您能否解释一下为什么 1 和 6 不是可调用类型?
  • 此外,即使functors 不是核心语言概念的一部分,您是否同意 3(并且只有 3)对应于函子的传统概念(如在其他编程语言中所见) ?
  • "a) 引用 #1,b) #2,c) 引用 #2" 读起来非常尴尬 :-) +1。
【解决方案2】:

我认为你错过了一些沿线的变化

  • 一个类,使得std::is_class_v<F>true,并且F 继承了一个operator()

至于闭包和 lambda,请注意 C++ 没有神奇的 lambda。 Lambda 只是类类型的对象,通过方便的语法创建。 std::bind 也会产生一个 Callable 对象,这也可以被认为是一个闭包。但正如 Nicol Bolas 在 cmets 中所指出的,“闭包”在 C++ 中是一个没有确切含义的标签,不应该出现在列表中。

【讨论】:

    猜你喜欢
    • 2021-08-08
    • 2012-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2018-01-11
    • 1970-01-01
    • 2021-02-26
    相关资源
    最近更新 更多