Рассмотрим требования для операнда встроенного унарного *
.
[expr.unary.op]/1:
The unary * operator performs indirection: the expression to which
it is applied shall be a pointer to an object type, or a pointer to a
function type and the result is an lvalue referring to the object or
function to which the expression points. ...
Но тип выражения nullptr
не является ни указателем на объект, ни указателем на функцию. На самом деле nullptr
имеет свой отдельный фундаментельный тип, который не может быть выражен средствами языка (как int
), не может быть классом или указателем.
[support.types.nullptr]/1:
The type nullptr_t is a synonym for the type of a nullptr
expression, and it has the characteristics described in
[basic.fundamental]
and [conv.ptr].
...
[cstddef.syn]:
namespace std {
...
using nullptr_t = decltype(nullptr);
...
}
[basic.fundamental]/14:
A value of type std::nullptr_t is a null pointer constant. ...
[basic.fundamental]/15:
The types described in this subclause are called fundamental types. ...
Хорошо, но ведь мы можем привести этот тип к указательному типу. Почему не происходит неявного преобразования? — Для того чтобы неявное преобразование вообще рассматривалось, необходимо чтобы существовал тип, к которому мы хотим привести.
[conv.general]/1:
...
A standard conversion sequence will be applied to an expression if
necessary to convert it to a required destination type.
У нас же такого типа нет (и это не может быть тип void
, т.к. это не объектный тип).
Ошибки вида "use of overloaded operator '*' is ambiguous" не может возникнуть, т.к. она подразумевает процесс overload resolution, который требует наличия хотя бы одного нефундаментального типа в операндах оператора. Другими словами, если все операнды оператора не являются классами/перечислениями, то overload resolution происходить не будет.
Если сделать преобразование к объектному типу явно, то целевой тип появится и всё будет работать:
int main() {
// *((void*)nullptr); // CE, not an object type
*((int*)nullptr); // OK, btw no UB
}