有没有理由我们无法在未评估的上下文中命名非静态成员函数?

时间:2017-11-13 11:55:56

标签: c++ language-lawyer

阅读[expr.prim.id]时,会看到

  

表示非静态数据成员或非静态数据的id表达式   只能使用类的成员函数:

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

上述子弹仅适用于数据成员这一事实对我来说并不清楚。直观地说,我希望以下内容形成良好:

#include <type_traits>

using func = int();

class bar {
  func foo; // This is valid, and not the subject of the question
};

static_assert(std::is_same<decltype(bar::foo), func>::value, "No Symmetry!");

但是,即使在检查静态断言之前,decltype()也是不正确的。

是否有一些我不知道的歧义?

3 个答案:

答案 0 :(得分:3)

  

是否有一些我不知道的歧义?

事实上,有很多类型信息被添加为该成员函数声明的一部分。

虽然func当然可以用来宣告该成员,但故事并未在此结束。声明成员后,它的类型就完成了。这涉及添加其他一些东西,例如 cv-qualifers ref-qualifiers 。在foo的情况下,确定所有默认的隐式,并且它们成为bar::foo类型的一部分。由[dcl.fct]/8指定:

  

返回类型,参数类型列表,引用限定符,   cv-qualifier-seq和异常规范,但不是默认规范   参数,是函数类型的一部分。

foo的上述声明中无法明确指定它们(尽管它们可能会被添加到func),但它们可能会被添加:

class bar {
  int foo() const volatile &&;
};

它们是函数类型的一部分,decltype(bar::foo)应该在它们出现时解决它们(如果我正确收集,即使它们没有),也可以解决它们。

当我们尝试评估const volatile &&时,decltype(bar::foo)会去哪儿?

  • 应该被忽略吗?那可以做到。但丢失类型信息很少是件好事。
  • 我们应该保留它,并且类型decltype计算为指向成员函数的指针吗? 这也可行,但现在它与数据成员在未评估的上下文中命名时的行为方式不同。我们引入了一个差异。
  • 是否应保留,并将类型解析为其他内容?也许像int(foo const volatile&&)int() const volatile &&(另一种函数类型)?这打破了人们期望的对称性,并且再次与数据成员产生差异。

没有简单或明显的方法可以让它始终运作良好。因此,对于看似有限使用的功能而言,不要使问题复杂化,最好将其视为不良形式。

答案 1 :(得分:0)

  

我是否有一些模棱两可的缺失?

我不这么认为。可能更需要评估非静态数据成员,而不是非静态成员函数。

但是,这个:

static_assert(std::is_same<decltype(bar::foo), func>::value, "No Symmetry!");

没有多大意义。 &bar::foo的类型不是func*,而是func bar::*。并且没有一种方法可以拼写没有指针,因此必须能够评估decltype(bar::foo)意味着引入全新的类型语法?看起来不值得。

请注意decltype(bar::foo)不能是func,因为func是函数类型,但bar::foo是成员函数。

答案 2 :(得分:-1)

我没有看到任何理由。

看看这个:

typedef void Func();

Func freeFunction;

struct Foo {
    Func memberFunction;
};

freeFunction的声明是Func freeFunction;。因此,decltype(freeFunction)void(),即Func

使用相同的逻辑,因为Foo::memberFunction也被声明为Func,我也希望decltype(Foo::memberFunction)也是Func。但事实并非如此,因为这不会编译。

就像int a; decltype(a)解析为int一样,即使int a;是成员,decltype(Foo::memberFunction)也应该没问题。

注意,也可以处理限定符,它们没有什么特别之处(当然,在这种情况下,Func只能用于声明非静态成员函数):

typedef void Func() const volatile &&;

struct Foo {
    Func memberFunction;
};

在这里,我希望decltype(Foo::memberFunction)void() const volatile &&,因此我可以复制其声明:

struct Bar {
    decltype(Foo::memberFunction) myMemFn;
};

引用C ++ 14标准(9.2 / 11):

  

[注意:非静态成员函数的类型是普通的   函数类型,非静态数据成员的类型是普通的   对象类型。没有特殊的成员函数类型或数据成员   类型。 - 结束说明]

这句话意味着,如果decltype(<member_function>)返回了一种普通函数,那将是明智的。