#c
#c
Вопрос:
Вот пример:
#include "type_traits"
#include "string"
template<typename T>
class Wrapper {
public:
explicit Wrapper(T amp;amp;t) : t_(std::forward<T>(t)) {}
T amp;Get() { return t_; }
private:
T t_;
};
int main() {
std::string s1;
Wrapper<std::string> w1(std::move(s1));
std::string s2;
Wrapper<std::string> w2(s2);
}
строка Wrapper<std::string> w1(std::move(s1));
будет скомпилирована, но строка Wrapper<std::string> w2(s2);
не будет, компилятор сообщает об ошибке:
конструктор-кандидат нежизнеспособен: нет известного преобразования из ‘std::string’ (он же ‘basic_string<char, char_traits<char>, allocator<char> >’) в ‘std::__1::basic_string<char> amp;amp;’ для 1-го аргумента
Для простоты я создаю foo
класс:
class Foo {
public:
Foo() {}
Foo(const Fooamp; ) {}
Foo(Fooamp;amp;) {}
};
и
Foo foo;
Wrapper<Foo> w3(foo);
Сообщает об этой ошибке:
нет известного преобразования из ‘Foo’ в ‘Foo amp;amp;’ для 1-го аргумента
Похоже, что «универсальная ссылка» не работает, вместо этого компилятор рассматривает первый параметр только как ссылку на значение rvalue.
Итак, что же я упускаю из виду?
Ответ №1:
Конструктор Wrapper::Wrapper
не является шаблоном, параметр просто не объявлен как ссылка пересылки. Учитывая Wrapper<std::string>
, Wrapper::Wrapper
всегда принимает параметр как rvalue-reference , т.е. std::stringamp;amp;
.
- параметр функции шаблона функции, объявленный как rvalue ссылка на cv-параметр шаблона неквалифицированного типа того же шаблона функции:
Вы можете создать шаблон конструктора для объявления параметра в качестве ссылки пересылки. например
template<typename T>
class Wrapper {
public:
template <typename X>
explicit Wrapper(X amp;amp;t) : t_(std::forward<X>(t)) {}
T amp;Get() { return t_; }
private:
T t_;
};
Комментарии:
1. Любой способ принудительно
T
использовать иX
тот же тип? В случае, если передается неправильный типX
, ноT
просто имеет конструктор соответствия?2.
{ static_assert(std::is_same_v<T,X>); }
или что-то в этом роде3. @psionic12 ЕСЛИ бы они не были одинаковыми, разве ошибка компилятора не переместилась бы просто в std::forward бит, где он пытается вызвать конструктор t_?
4. @JerryJeremiah например
Wrapper<Foo> w3(bar);
, еслиFoo
у вас есть конструктор, который может приниматьBar
тип, он будет компилироваться, но это не то, что я хочу.