Почему F (F) & конструктор вызывается вместо F (F & &) конструктор в конструктор класса G?
Потому что f
является lvalue. Несмотря на то, что это связан с rvalue, и его тип имеет значение rvalue для F
, это также с именем variable. Это делает его lvalue. Не забывайте, что категория значений объекта не определяется по типу и наоборот.
Когда вы передаете значение lvalue функции, к ней могут привязываться только ссылки lvalue. Вы должны изменить код следующим образом, если вы хотите, чтобы поймать rvalues только:
class G {
F f_;
public:
G(F&& f) : f_(std::move(f)) {
std::cout << "G()" << std::endl;
}
};
В качестве альтернативы, вы можете использовать std::forward<>()
, что эквивалентно в этом случае, но делает ваше намерение пересылкиf
еще очевиднее:
class G {
F f_;
public:
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
};
Теперь это последнее определение легко распространяется, так что оба lvalues и rvalues типа F
могут быть связаны с параметром f
:
class G {
F f_;
public:
template<typename F>
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
};
Это позволяет, например, построить Экземпляр G
таким образом:
F f;
G g(f); // Would not be possible with a constructor accepting only rvalues
Эта последняя версия имеет нюанс хотя: ваш конструктор will basically work as a copy-constructor as well, так что вы можете явно определить все возможные конструкторы копирования, чтобы избежать неловких ситуаций:
class G {
F f_;
public:
template<typename F>
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
G(G const&) = default;
G(G&); // Must be defaulted out-of-class because of the reference to non-const
};
G::G(G&) = default;
Поскольку функции нешаблонных предпочтительнее инстанциации шаблонов функций, копия конструктора Виль l выбирается при построении объекта G
другого объекта G
. То же самое относится, конечно, к конструктору . Это остается как упражнение.
@ AndyProwl: Я говорю это: http://stacked-crooked.com/view?id=7f047abd729b8347039874dc9a5e8b7f18aa934a8d82d638dde2147aa94cac94. Прочитайте комментарии. – Nawaz
@ Наваз: О, да, теперь я вижу вашу точку. Вы правы, я должен был объявить как const, так и неконвертную версию конструктора эксплицитных копий, иначе шаблон конструктора будет выбран в любом случае. Отредактировано, спасибо. –
+1. Теперь это точно! – Nawaz