Re[2]: При выводе типа функции теряется ссылка.
От: Сыроежка  
Дата: 31.05.12 19:58
Оценка: 1 (1) -1 :)
Тоже самое написано и в разделе "14.8.2.4 Deducing template arguments during partial ordering":

"— If A is a reference type, A is replaced by the type referred to."
Меня можно встретить на www.cpp.forum24.ru
Re: При выводе типа функции теряется ссылка.
От: Сыроежка  
Дата: 31.05.12 19:52
Оценка: -1 :)
Здравствуйте, Went, Вы писали:

W>1. Почему тип T выводится как int, а не как int&?

W>2. Чем руководствовались разработчики стандарта?
W>3. Как это обойти?

W>Спасибо.


Просматривая бегло стандарт, я нашел к примеру в разделе "14.8.2.3 Deducing conversion function template arguments" следующее предложение:

"If A is a reference type, the type referred to by A is used for type deduction."

Если внимательно просмотреть стандарт, я думаю, можно найти аналогичное утверждение и для других случаев вывода параметров шаблона.
Меня можно встретить на www.cpp.forum24.ru
Re: При выводе типа функции теряется ссылка.
От: rg45 СССР  
Дата: 31.05.12 21:10
Оценка: 2 (1)
Здравствуйте, Went, Вы писали:

W>Здравствуйте. Вопрос, наверное, ламерский, но меня такое очень удивило.

W>Итак, такой код:
W>
W>template<typename T>
W>void f(T x)
W>{
W>}
W>void main()
W>{
W>  int i = 0;
W>  int& ri = i;
W>  f(ri);
W>}
W>


W>1. Почему тип T выводится как int, а не как int&?


Тебя же не удивляет, что T выводится как int при передаче в эту функцию i вместо ri? А между тем, выражения i и ri имеют одинаковый тип — lvalue of int, а значит и результат выведения типов для них одинаков.

Почему сделали так, а не иначе? Ну, вероятно, не захотели брать на себя ответственность за сюрпризы, которые могут случаться при подобных сценариях:
template<typename T>
void f(T x)
{
  x = foo(); //T is reference? An outer variable is modified!
}


Если нужно, все-таки, чтобы параметр передавался по ссылке, ты этого можешь добиться различными способами: явно указать тип шаблонного параметра при вызове функции, использовать ссылку при объявлении формального параметра шаблонной функции, определить несколько перегрузок одноименной шаблонной функции, и т.д. в зависимости от задачи. Главное, что при этом ты никому не подложишь "сюрпризов".
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: При выводе типа функции теряется ссылка.
От: Кодт Россия  
Дата: 31.05.12 21:57
Оценка: +1
Здравствуйте, Went, Вы писали:

W>Здравствуйте, rg45, Вы писали:

R>> определить несколько перегрузок одноименной шаблонной функции
W>Да, это то, что надо. Спасибо!

Но различать i и ri таким способом ты всё равно не сможешь

Лучше расскажи, что за задачу ты решаешь.
Перекуём баги на фичи!
При выводе типа функции теряется ссылка.
От: Went  
Дата: 31.05.12 19:15
Оценка:
Здравствуйте. Вопрос, наверное, ламерский, но меня такое очень удивило.
Итак, такой код:
template<typename T>
void f(T x)
{
}
void main()
{
  int i = 0;
  int& ri = i;
  f(ri);
}


1. Почему тип T выводится как int, а не как int&?
2. Чем руководствовались разработчики стандарта?
3. Как это обойти?

Спасибо.
Re: При выводе типа функции теряется ссылка.
От: Vamp Россия  
Дата: 31.05.12 20:16
Оценка:
W>1. Почему тип T выводится как int, а не как int&?
Ответили.
W>2. Чем руководствовались разработчики стандарта?
А как иначе? Для ссылок выводить аргумент как ссылку? Это совершенно не обязательно то, чего человек хочет.
W>3. Как это обойти?
Просто:

void f(T& x)
{
}



W>Спасибо.

Не за что.
Да здравствует мыло душистое и веревка пушистая.
Re: При выводе типа функции теряется ссылка.
От: Masterkent  
Дата: 31.05.12 20:35
Оценка:
Went:

W>1. Почему тип T выводится как int, а не как int&?


См. C++11 — 14.8.2.1.

W>2. Чем руководствовались разработчики стандарта?


Своей интуицией, наверное.

W>3. Как это обойти?


Зависит от того, что тебе надо получить.
Re[2]: При выводе типа функции теряется ссылка.
От: Went  
Дата: 31.05.12 21:30
Оценка:
Здравствуйте, rg45, Вы писали:
R> определить несколько перегрузок одноименной шаблонной функции
Да, это то, что надо. Спасибо!
Re[4]: При выводе типа функции теряется ссылка.
От: Went  
Дата: 01.06.12 10:45
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Но различать i и ri таким способом ты всё равно не сможешь

Авв. Действительно. Если перегрузить и для значения, и для ссылки, идет неоднозначность вызова

К>Лучше расскажи, что за задачу ты решаешь.

Есть тип Variant. Может хранить объект любого типа, хоть ссылку, хоть указатель, хоть сам объект. Хотелось бы такого:
int x;
int& rx = x;
Variant v;
v.set(x); // v хранит сам объект
v.set(rx); // v должен хранить ссылку на объект (внутри реализовано через указатель, но это детали), но он не отличает это от верхней строчки

Если я пишу явно
v.set<int&>(rx);

то все работает как надо.

Я не уверен, что мне обязательно нужно без явного указания. Но хочется все-таки такую возможность иметь.
Re[5]: При выводе типа функции теряется ссылка.
От: Masterkent  
Дата: 01.06.12 11:07
Оценка:
Went:

W>Хотелось бы такого:

W>
W>int x;
W>int& rx = x;
W>Variant v;
W>v.set(x); // v хранит сам объект
W>v.set(rx); // v должен хранить ссылку на объект (внутри реализовано через указатель, но это детали), но он не отличает это от верхней строчки

Это странное и нереализуемое желание. Шаблон функции никак не может определить, что ему передали аргументом — ссылку или не ссылку.
Re[5]: При выводе типа функции теряется ссылка.
От: rg45 СССР  
Дата: 01.06.12 11:25
Оценка:
Здравствуйте, Went, Вы писали:


К>>Лучше расскажи, что за задачу ты решаешь.

W>Есть тип Variant. Может хранить объект любого типа, хоть ссылку, хоть указатель, хоть сам объект. Хотелось бы такого:
W>
W>int x;
W>int& rx = x;
W>Variant v;
W>v.set(x); // v хранит сам объект
W>v.set(rx); // v должен хранить ссылку на объект (внутри реализовано через указатель, но это детали), но он не отличает это от верхней строчки
W>

W>Если я пишу явно
W>
W>v.set<int&>(rx);
W>

W>то все работает как надо.

W>Я не уверен, что мне обязательно нужно без явного указания. Но хочется все-таки такую возможность иметь.


ИМХО, это правильно, что такой возможности нет. Она чревата неожиданностями.

К примеру, как по-твоему должны бы отработать следующие случаи:
MyIncrementable& foo();
MyIncrementable x;
Variant v;
v.set(x);
v.set(++x);
v.set(foo());

?
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: При выводе типа функции теряется ссылка.
От: existential  
Дата: 01.06.12 12:07
Оценка:
Здравствуйте, Went, Вы писали:

W>Есть тип Variant. Может хранить объект любого типа, хоть ссылку, хоть указатель, хоть сам объект. Хотелось бы такого:

W>
W>int x;
W>int& rx = x;
W>Variant v;
W>v.set(x); // v хранит сам объект
W>v.set(rx); // v должен хранить ссылку на объект (внутри реализовано через указатель, но это детали), но он не отличает это от верхней строчки
W>

W>Если я пишу явно
W>
W>v.set<int&>(rx);
W>

W>то все работает как надо.

W>Я не уверен, что мне обязательно нужно без явного указания. Но хочется все-таки такую возможность иметь.


decltype(x) и decltype(rx) будут разными типами, int и int&, соответственно. Можно этим воспользоваться, обернув всё в макрос, чтобы избежать повтора.
Как-то так:
#define VARIANT_SET(v, x) v.set<decltype(x)>(x)

Но вообще я не стал бы так делать
Re[6]: При выводе типа функции теряется ссылка.
От: Went  
Дата: 01.06.12 18:09
Оценка:
Здравствуйте, rg45, Вы писали:
R>ИМХО, это правильно, что такой возможности нет. Она чревата неожиданностями.

Да. Чем больше думаю, тем больше соглашаюсь
Re[5]: При выводе типа функции теряется ссылка.
От: Erop Россия  
Дата: 01.06.12 20:39
Оценка:
Здравствуйте, Went, Вы писали:


W>Я не уверен, что мне обязательно нужно без явного указания. Но хочется все-таки такую возможность иметь.


Так ты можешь и просто int засунуть, как ссылку

По идее это должно быть два разных метода.
Типа Set и SetRef
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: При выводе типа функции теряется ссылка.
От: Кодт Россия  
Дата: 01.06.12 21:09
Оценка:
Здравствуйте, Went, Вы писали:

W>Есть тип Variant. Может хранить объект любого типа, хоть ссылку, хоть указатель, хоть сам объект.

<>
W>Я не уверен, что мне обязательно нужно без явного указания. Но хочется все-таки такую возможность иметь.

Лучше, всё же, делать явные указания.
Потому что
1) компилятор не может отличить (или, по крайней мере, сообщить это тебе) характер ссылки — на временный объект, на локальный объект, на внешний...
2) иногда нужно передать значение, получаемое из lvalue (например, разыменовав указатель); не делать же промежуточную rvalue-копию ради этого.
3) опять же, константность-неконстантность

Возможно, что достаточно просто отказаться от хранения в варианте ссылок. Только значения и указатели (которые — тоже значения).
Если нужно ввести третью категорию данных — заведомо ненулевые указатели, то посмотри в сторону boost/std(C++11) :: ref, cref.
Это избавит от необходимости в методах Set/SetRef/SetCRef.

Также возможно, что нет нужды изобретать велосипед: boost::any — вариант, который может хранить любые значения.
Перекуём баги на фичи!
Re[6]: При выводе типа функции теряется ссылка.
От: Went  
Дата: 02.06.12 12:53
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Также возможно, что нет нужды изобретать велосипед: boost::any — вариант, который может хранить любые значения.
Основная фишка моего Variant, это возможность бинарной сериализации, которую boost::any по своей природе не тянет, ИМХО. Ну, там хранится буфер данных и указатель в таблице дескрипторов типа. Хранить ссылки, конечно, это экзотика, но хочется полного охвата.
Re[7]: При выводе типа функции теряется ссылка.
От: zaufi Земля  
Дата: 04.06.12 14:30
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Кодт, Вы писали:

К>>Также возможно, что нет нужды изобретать велосипед: boost::any — вариант, который может хранить любые значения.
W>Основная фишка моего Variant, это возможность бинарной сериализации, которую boost::any по своей природе не тянет, ИМХО. Ну, там хранится буфер данных и указатель в таблице дескрипторов типа. Хранить ссылки, конечно, это экзотика, но хочется полного охвата.

не есть еще вариант с boost::ref() (и boost::reference_wrapper) или, если у тебя C++11, std::ref()/std::cref() с тем же std::reference_wrapper.
для враппера можно сделать специализацию и тут уже будет явно понятно что вызывающий хочет именно ссылку...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.