Хочется услышать ваше мнение на счет следующе проблемки
Вот пример кода:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void DoSomethig() = 0;
};
class Concrete : public Base
{
public:
Concrete(int data) {}
virtual void DoSomethig()
{
cout << "DoSomethig" << endl;
}
};
void DoSomething(Base& base)
{
base.DoSomethig();
}
int main()
{
DoSomething( Concrete(100) );return 0;
}
Так вот при компиляции gcc 2.96 ругается
test.cpp:31: could not convert `Concrete(100)' to `Base &'
test.cpp:25: in passing argument 1 of `DoSomething (Base &)'
При компиляции на VC6 все нормально
Если же заменить выделенную строчку на следующий код, то все пучком
Concrete c(100);
DoSomething(c);
Также если заменить void DoSomething(Base& base) на void DoSomething(const Base& base) и сделать метод Base::DoSomethig константным, то тоже все пучком.
Интересно, это я что-то не так делаю или gcc кривой?
__________________________________
Василий Черневич (aka Willi)
Временный объект можно привязать только к константной ссылке
W>Если же заменить выделенную строчку на следующий код, то все пучком W>
W> Concrete c(100);
W> DoSomething(c);
W>
Здесь нет временного объекта — все нормально
W>Также если заменить void DoSomething(Base& base) на void DoSomething(const Base& base) и сделать метод Base::DoSomethig константным, то тоже все пучком.
см. выше.
W>Интересно, это я что-то не так делаю или gcc кривой?
Здравствуйте, naje, Вы писали:
N>Здравствуйте, jazzer, Вы писали:
J>>Временный объект можно привязать только к константной ссылке
N>а что действительно vc6 такое компилирует :???:
W>Я не возмущаюсь. Я просто хочу понять, чем чревато написание подобного кода на VC.
Тем, что ты попытаешься изменить объект, переданный по неконстантной ссылке и будеь очень долго удивляться, куда деваются твои изменения.
Здравствуйте, Willi, Вы писали:
W>Здравствуйте, jazzer, Вы писали:
J>>Временный объект можно привязать только к константной ссылке
W>Это стандарт так велит? W>А есть ли внятное объяснение такому требованию?
W>И почему тогда VC это компилит? Более того мне сказали что gcc 3 это тоже компилит.
W>Я не возмущаюсь. Я просто хочу понять, чем чревато написание подобного кода на VC.
Строго говоря, рчеь идет не о временном объекте, а об rvalue.
Т.е. Concrete(100) — это rvalue типа Concrete.
Так же как 2 — это rvalue типа int.
Представь себе функцию
void f(int&i)
{
i++;
}
ты ее можешь вызвать для реального объекта:
int i;
f(i);
после чего у тебя i увеличится на единицу, но бессмысленно вызывать ее для rvalue:
f(2);
Что в таком случае должно увеличиваться?
У тебя нет объекта, с которым ты мог бы работать, есть только значение, с которым ты в принципе ничего сделать не можешь — ты не можешь из двойки сделать тройку по определению.
Здравствуйте, Willi, Вы писали:
J>>Временный объект можно привязать только к константной ссылке
W>Это стандарт так велит?
Да, это стандарт так велит. W>А есть ли внятное объяснение такому требованию?
За другими примерами — в поиск. Эта тема обсуждалась не раз, и приводились аргументы и "за" и "против"
W>И почему тогда VC это компилит? Более того мне сказали что gcc 3 это тоже компилит.
Потому что это нестандартное расширение, о чем компилятор выдает соответствующее предупреждение:
VC6:
warning C4239: nonstandard extension used : 'argument' : conversion from 'struct test' to 'struct test &'
A reference that is not to 'const' cannot be bound to a non-lvalue
кстати это расширение не работает для встроенных типов.
W>Я не возмущаюсь. Я просто хочу понять, чем чревато написание подобного кода на VC.
Тем, что этот код не будет компилироваться другими компиляторами.
Стандарт прямо запрещает связывание неконстантных ссылок с rvalue, в том числе, с временными объектами. Однако, данное правило является компромисным.
На самом деле, в ряде случаев связывание ссылки с временным объектом имеет смысл. Поэтому VC при включённых расширениях языка позволяет это делать.
На мой взгляд, наилучшим решением было бы запрещение связывание неконстантных ссылок с POD типами и разрешение для остальных.