是否存在对类型名有效但对基本类型无效的语言结构?

时间:2015-11-28 01:43:10

标签: c++

我注意到伪析构函数调用在使用类型名称时有效,但在使用基本类型时则无效。

typedef int BType;
int b;
b.~BType();   // Legal
b.~int();     // Not legal

可以在an answer to another SO post找到对上述内容的解释。

来自C ++ 11标准的类型名称的定义:

  

7.1.6.2简单类型说明符,p1

type-name:  
   class-name   
   enum-name  
   typedef-name  
   simple-template-id

当类型说明符是类型名称时,是否有任何其他语言结构有效,但即使 type-name ,它也是基本类型时无效代表一种基本类型,如上所示?

2 个答案:

答案 0 :(得分:4)

我认为你不会发现任何其他案件。如果我们查看草案C ++标准附件A语法摘要,我们可以看到 type-name 显示的语法中唯一的其他位置是:

nested-name-specifier:
  ::
  type-name ::
  namespace-name ::
  decltype-specifier ::
  nested-name-specifier identifier ::
  nested-name-specifier templateopt simple-template-id ::

simple-type-specifier:
  nested-name-specifieropt type-name
  [...]

这两者都没有提供类似的机会,我们得到的pseduo-destructor具有以下语法:

pseudo-destructor-name:
  nested-name-specifieropt type-name :: ~ type-name
  nested-name-specifier template simple-template-id :: ~ type-name
  nested-name-specifieropt~ type-name
  ~ decltype-specifier 

并在5.2.4 [expr.pseudo]部分​​中介绍,该部分规定了我们看到的行为:

  

在点后使用伪析构函数名称。或箭头 - >操作者   表示由type-name表示的非类类型的析构函数   或decltype-specifier。结果只能用作操作数   对于函数调用operator(),以及这样的调用的结果   类型无效。唯一的影响是后缀表达式的评估   在点或箭头之前。

另一方面,我们可以在3.4.3 [basic.lookup.qual] 部分看到嵌套名称说明符的规则,禁止这样的情况:

  

可以引用类或命名空间成员或枚举器的名称   在:: scope resolution operator(5.1)应用于之后   nested-name-specifier,表示其类,名称空间或   列举。如果是:: scope解析运算符   nested-name-specifier之前没有decltype-specifier,lookup   之前的名称::仅考虑名称空间,类型和   专业化类型的模板。如果找到的名称没有   指定命名空间或类,枚举或依赖类型,   节目形成不良

简单类型说明符的情况不会让我们在那里,因为基本类型已经可以接受这种情况。

答案 1 :(得分:2)

当函数的返回类型是基本类型时,存在差异:

struct X{};

template <class T> auto foo() {
  // one liner
  []() -> T { return T{}; }() = T{}; // invalid for T fundamental type

  // or more clear:
  auto get_t = []() -> T { return T{}; };
  get_t() = T{}; // invalid for T fundamental type
}

auto main() -> int {
  foo<X>();    // valid
  foo<int>();  // invalid
  return 0;
}

没有模板,更加清晰:

struct X{};

auto ret_x() -> X { return X{}; }    
auto ret_int() -> int { return int{}; }


auto main() -> int {
  ret_x() = X{};     // valid
  ret_int() = int{}; // invalid
  return 0;
}

基本类型的rvalues无法修改。对于其他类型显然不是这种情况,例如,移动操作必须修改它移动的临时值(例如,使拥有指针为nullptr)