Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there language constructs that are valid for type-name but not for fundamental types?

Tags:

c++

I noticed that pseudo destructor call is valid when a type-name is used but not when a fundamental type is used.

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

An explanation for the above can be found at an answer to another SO post.

Definition of type-name, from the C++11 Standard:

7.1.6.2 Simple type specifiers, p1

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

Are there any other language constructs that are valid when the type specifier is a type-name but not valid when it is a fundamental type even when the type-name represents a fundamental type, as shown above?

like image 842
R Sahu Avatar asked Nov 28 '15 01:11

R Sahu


2 Answers

I do not think you will find any other cases. If we look at the draft C++ standard Annex A Grammar summary we can see the only other locations in the grammar where type-name shows up are:

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

and:

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

Neither of which provide a similar opportunity that we get with the pseduo-destructor which has the following grammar:

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 

and is covered in section 5.2.4 [expr.pseudo] which provides for the behavior we see:

The use of a pseudo-destructor-name after a dot . or arrow -> operator represents the destructor for the non-class type denoted by type-name or decltype-specifier. The result shall only be used as the operand for the function call operator (), and the result of such a call has type void. The only effect is the evaluation of the postfix-expression before the dot or arrow.

on the other hand we can see the rules for nested-name-specifier in section 3.4.3 [basic.lookup.qual] forbid such a case:

The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator (5.1) applied to a nested-name-specifier that denotes its class, namespace, or enumeration. If a :: scope resolution operator in a nested-name-specifier is not preceded by a decltype-specifier, lookup of the name preceding that :: considers only namespaces, types, and templates whose specializations are types. If the name found does not designate a namespace or a class, enumeration, or dependent type, the program is ill-formed

The simple-type-specifier case does not get us there either since fundamental types are already acceptable for this case.

like image 200
Shafik Yaghmour Avatar answered Nov 14 '22 11:11

Shafik Yaghmour


There is a difference when the return type of a function is a fundamental type or not:

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;
}

Without templates, to be even more clear:

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 for fundamental types cannot be modified. This is clearly not the case for other types, as, for instance, a move operation must modify the temporary from which it moves (e.g. make the owning pointer nullptr)

like image 35
bolov Avatar answered Nov 14 '22 11:11

bolov