Это тангенциальное продолжение моего предыдущего вопроса Адрес функции, соответствующей перегрузке bool vs const void *. Ответчик объяснил:
Стандарт [С++ 11] не определяет стандартные преобразования из "указатель на функцию" на "указатель на
void".Трудно представить цитату из-за отсутствия чего-то, но ближайший я могу сделать это С++ 11 4.10/2 [conv.ptr]:
Значение типа "указатель на cv
T", , гдеTявляется типом объекта, может быть преобразовано в значение prvalue типа "указатель на cvvoid". Результат преобразования указателя на cvT"на " указатель на cvvoid" указывает на начало места хранения где объект типаTнаходится, как если бы объект был наиболее (1.8) типа T (т.е. не подобъект базового класса). Значение нулевого указателя преобразуется в значение нулевого указателя тип назначения.(акцент мой)
Предполагая, что func объявлен void func();, если вы выполняете C-стиль, т.е. (void*) func, приведение будет успешным. static_cast<void*>(func) однако недействителен, но reinterpret_cast<void*>(func) будет успешным. Однако вы не можете сделать преобразованный преобразованный указатель обратно в исходный. Например,
Fine:
int main() {
int* i;
void* s = static_cast<void*>(i);
i = static_cast<int*>(s);
s = reinterpret_cast<void*>(i);
i = reinterpret_cast<int*>(s);
}
Неплохо:
void func() { }
int main() {
void* s = reinterpret_cast<void*>(func);
reinterpret_cast<decltype(func)>(s);
}
N3337 начинается, говоря:
[expr.reinterpret.cast]
Результат выражения
reinterpret_cast<T>(v)является результатом преобразуя выражениеvв типT. ЕслиT- значение lvalue ссылочного типа или ссылки на тип функции, результат lvalue; еслиTявляется ссылкой rvalue на тип объекта, результатом является значение x; в противном случае результатом является значение prvalue и значение lvalue-to-rvalue (4.1), от массива к указателю (4.2) и стандартного стандарта (4.3) преобразования выполняются над выражением v. Конверсии, которые могут быть выполняемые явно с использованиемreinterpret_cast, перечислены ниже. нет другое преобразование может быть выполнено явно с помощьюreinterpret_cast.
Я выделил язык, который, по моему мнению, является ключевым. Последняя часть, по-видимому, подразумевает, что если конверсия отсутствует в списке, она является незаконной. Вкратце, разрешенные преобразования:
- Указатель может быть явно преобразован в любой целочисленный тип, достаточно большой для его хранения.
- Значение типа интегрального типа или перечисления может быть явно преобразовано в указатель.
- Указатель функции может быть явно преобразован в указатель функции другого типа.
- Указатель объекта может быть явно преобразован в указатель объекта другого типа.
- Преобразование указателя функции в тип указателя объекта или наоборот условно поддерживается.
- Значение нулевого указателя (4.10) преобразуется в значение нулевого указателя для типа назначения.
- Значение prawue типа "указатель на член
XтипаT1" может быть явно преобразовано в prvalue другого типа "указатель на элемент Y типаT2", еслиT1иT2 - оба типа функций или оба типа объектов. - Выражение lvalue типа
T1может быть передано типу "ссылка наT2", если выражение типа "указатель наT1" может быть явно преобразовано в тип "указатель наT2" используя reinterpret_cast.
void* не является указателем на функцию, а объекты не имеют функции или типа void.
[basic.types]
Тип объекта - это (возможно, cv-квалифицированный) тип, который не является тип функции, а не тип ссылки, а не тип void.
Так что, возможно, я хватаюсь за соломинку, но кажется, что reinterpret_cast<void*>(func) является незаконным. Однако, с другой стороны, [expr.static.cast]/5 говорит: "В противном случае static_cast должен выполнить одно из перечисленных ниже преобразований.
выполняется явным образом с помощью static_cast. "Ключевое различие заключается в том, что" должен "и" может ". Достаточно ли сделать законный reinterpret_cast закон или я пропущу что-то еще?