Привет. Есть класс, принимающий объект, и складирующий его во внутренний контейнер. Можно ли сделать так, чтобы прием объекта и по константной ссылке, и по rvalue-ссылке укладывался в один метод? Сейчас приходится делать так: Код (Text): template <class T> class some_container { public: void push(T const& val) { values.push_back(val); } void push(T&& val) { values.push_back(val); } private: std::vector<T> values; }; А хочется чтобы все укладывалось в один some_container::push.
Код (Text): template <class T> class some_container { public: template <class U> void push(U val) { values.push_back(val); } private: std::vector<T> values; };
sergegers Хм, все это очень странно! MSVS 2010: Код (Text): template <class T> class some_container { public: template <class U> void push(U val) { values.push_back(val); // Тут вызывается const& std::make_pair(val, val); // Тут вызывается && } private: std::vector<T> values; }; int main() { some_container<std::string> sc; sc.push(std::string("lalala")); return 0; } И самое странное, что если заменить void push(U val) на void push(T&& val), то для vector::push_back всеравно вызывается const&, хотя реализация move-push_back в студийном STL есть, и интелисенс ее находит. Что я делаю не так?
sergegers Не, так тоже не хочет. Да и rvalue должно само сводиться к вызову &&, без move. Например здесь все ок, вызывается && Код (Text): void nya(std::string const& s) { } void nya(std::string&& s) { } int main() { nya(std::string("lalala")); return 0; }
а, похоже вот так надо Код (Text): template <class T> class some_container { public: template <class U> void push(U val) { values.push_back(std::forward<U>(val)); } private: std::vector<T> values; };
sergegers Миша, все х##ня Делов в том, что U выводится в std::string (не ссылка, не rvalue, а просто std::string), и ее копия создается еще до вызова: sc.push(str); // Вот тут Далее-то да, происходит move, но смысла в нем нет, потому что копия уже создана. Поэтому до сих пор не ясно: 1. Можно ли обойтись одним методом. 2. Почему у вектора push_back && не вызывается, а в моем примере с nya && - вызывается? В чем разница?
sergegers А я тоже написал, что move происходит для копии, созданной в момент вызова, в связи с чем весь смысл move теряется. А в чем было дело, я, кажется, понял. Смотри что происходит: Код (Text): void mimimi(std::string const& s) { } void mimimi(std::string&& s) { } void nya(std::string const& s) { mimimi(s); } void nya(std::string&& s) { mimimi(s); // mimimi const& ! } int main() { mimimi(std::string("lalala")); // mimimi && nya(std::string("lalala")); // nya && Как будто rvalue-ность видна только на самом первом этаже, и далее не передается.
sergegers Так, привожу на твоем же примере. Заменяем main вот на это: Код (Text): int main(int argc, char* argv[]) { ccc c; a a1; c.push(a1); return 0; } И видим в аутпуте: Код (Text): Create Copy Move Destroy Destroy Destroy Объект существовал в трех экземплярах. А должен был - в двух. Это произошло потому что U вывелся в std::string и в месте вызова push была создана копия объекта. move нужен для того чтобы избежать лишних копий, а тут мы наоборот получили +1 лишнюю. Если void push(U val) заменить на void push(U& val), то объект будет существовать в двух экземплярах, а copy-конструктор не будет вызван - то есть так, как и должно быть. В этом и есть мой изначальный вопрос - можно ли в одном вызове совместить move rvalue и передачу по const& lvalue. В твоем примере второе не работает - вместо передачи по ссылке происходит копирование объекта и его последующий move.
Такая же херня происходит с std::make_pair, так что в случае с неанонимными объектами надо явно применять std::move. http://ideone.com/3TY3L Как это следует из стандарта я вычислять не готов. Видимо, это лучшее, на что способен move конструктор
sergegers Самое забавное вот что: Код (Text): void mimimi(std::string const& s) { } void mimimi(std::string&& s) { } void nya(std::string const& s) { mimimi(s); } void nya(std::string&& s) { mimimi(s); // mimimi const& std::make_pair(s, s); // make_pair &&, && <--- !!! } int main() { nya(std::string("lalala")); // nya && return 0; } Ща пока нет времени вникать, продолжу чуть позже. Вопрос с make_pair в моем случае пока что не ясен.
В одном случае перегрузка функции, а в другом вывод типа аргумента шаблонной функции. Надо сравнивать правила.