Неявное преобразование типа со ссылкой на void*

Я хочу написать функцию, которая изменяет заданный указатель любого типа; поэтому я объявил, что моя функция принимает void*&, полагаясь на неявное преобразование любого указателя в void*. Однако следующий код отказывается компилироваться, говоря, что он не может преобразовать int*в void*&.

void f(void*& x)
{   
     x = 0; 
}

int main() {

    int* a = new int;
    f(a);
    delete a;
    return 0;
}

Обратите внимание, что он отлично работает, если f объявлено принимающим int*& (но затем теряет свою универсальность) или если f объявлено принимающим void* (но тогда f может изменять свой аргумент только локально).

Таким образом, независимо работает правило неявного преобразования «любое T* в void*», правило неявного преобразования «T в T&» работает, но не оба одновременно? Почему это так? Что я здесь сделал не так?

(Я знаю, что мог бы использовать шаблонную функцию для f, это в основном из любопытства).


person Louen    schedule 07.10.2013    source источник
comment
stackoverflow.com/ вопросов/399003/ нет гарантии, что sizeof(int *) == sizeof(double *) - поэтому нет способа сгенерировать код без шаблона, который делает то, что вы хотите.   -  person Karoly Horvath    schedule 07.10.2013
comment
@KarolyHorvath: void* всегда достаточно большой, чтобы вместить указатель на любой объект. Также спорно, является ли возможная разница в размерах (кстати, нигде не замеченная в реальных реализациях) указателей объектов реальной и предполагаемой или просто придирчивой интерпретацией разбросанной стандартной формулировки.   -  person PlasmaHH    schedule 07.10.2013
comment
@PlasmaHH: я не уверен, что вы намеревались передать этим ... должен ли код просто обнулить ячейку памяти для пустоты * (которая достаточно велика), потенциально перезаписав ячейку памяти другой переменной?   -  person Karoly Horvath    schedule 07.10.2013
comment
@KarolyHorvath: помимо того, что он не компилируется (поскольку временные объекты не могут привязываться к неконстантным ссылкам), если бы это было законно, оно, скорее всего, делало бы задуманное, потому что возможная разница в размерах указателей объектов является чисто теоретической, как и предположения о возможном поведении недопустимой языковой конструкции.   -  person PlasmaHH    schedule 07.10.2013
comment
Рассмотрим случай, когда вместо 0 в f вы написали new std::vector<int>. Вы понимаете, насколько безопасным было бы это преобразование?   -  person molbdnilo    schedule 07.10.2013
comment
то, что вы называете чисто теоретическим, называется стандартом. Думаю, мы с самого начала прекрасно поняли друг друга, поэтому весь этот разговор бессмыслен.   -  person Karoly Horvath    schedule 07.10.2013


Ответы (2)


Это потому, что эталонный бит. Ссылка на указатель одного типа — это не то же самое, что ссылка на указатель другого типа.

Конечно, это можно решить с помощью шаблонов:

template<typename T>
void f(T*& x) { ... }
person Some programmer dude    schedule 07.10.2013

Если бы это работало здесь, вы бы создали временный void* из T* (поскольку преобразование здесь действительно означает «создать новый объект другого типа»), к которому вы затем привязали бы ссылку, что не будет работать, так как это неконстант. Что будет работать, хотя:

void f(void* const & x)
{   
     x = 0; 
}

Но это, вероятно, не то, что вы имели в виду, поскольку речь идет о временном, а не о int*.

person PlasmaHH    schedule 07.10.2013