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?
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With