你如何获得成员函数的类型

时间:2017-11-23 12:39:57

标签: c++ language-lawyer

问题的灵感来自标准[class.mem]

中的注释
  

非静态成员函数的类型是普通函数类型,非静态数据成员的类型是普通对象类型。没有特殊的成员函数类型或数据成员类型。

所以,我决定测试它

struct S
{
    using Fn = void();
    Fn foo;

    static_assert(std::is_same_v<decltype(foo), Fn>);
};

但在decltype(foo)处出现错误:无效使用非静态成员函数

如何获得成员函数的类型?或者笔记是假的?

注意:对数据成员执行此操作

是有效的
struct U
{
    int i;
    static_assert(std::is_same_v<decltype(i), int>);
};

注意2:我没有找到如何通过指向成员的指针获取类型

template<typename>
struct NotLikeThis;
template<typename C, typename R, typename... Args>
struct NotLikeThis<R (C::*)(Args...)>
{
    using type = R(Args...);
};

标准中的注释与此无关。

1 个答案:

答案 0 :(得分:0)

该标准明确指出您不能执行此操作。

[expr.prim.id]

2 id-expression表示类的非静态数据成员或非静态成员函数只能使用

(2.1) 作为class member access的一部分,其中对象表达式引用成员的类 58 或从该类派生的类,或者

(2.2) 形成指向成员([expr.unary.op])的指针,或者

(2.3) 如果该id-expression表示一个非静态数据成员,并且它出现在未评估的操作数中。

[示例:

struct S {
  int m;
};
int i = sizeof(S::m);           // OK
int j = sizeof(S::m + 42);      // OK

-结束示例 ]

请注意,我对的强调只能使用:这些是可以使用表示成员函数的表达式的唯一方法。您想出的其他任何方法都是错误的。

请注意,2.3正是您想要的-在未评估的上下文(即S::m)中使用mdecltype是成员函数),但是它特别是(并且我认为故意)仅适用于 data 成员。

我可以想到至少允许这样做的一种含义(请参阅下文)。可能还有更多。

  • 我们假设m被声明为void m();,并且它是类S的成员。如果decltype(S::m)有效,则std::add_pointer<decltype(S::m)>也应该有效。
    考虑到成员函数具有隐式this参数, 第二种是什么? void (S::*)()或其他内容 像void (*)(S*)一样?甚至void (*)()?对于我们来说,显而易见的是我们想要void (S::*)(),但是知道S::m只是一个常规函数类型,为什么add_pointer会把它变成一个指向成员的指针?它甚至如何区分它?