Универсальная ссылка, похоже, не работает, компилятор принимает параметры как r-значение

#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; .

  1. параметр функции шаблона функции, объявленный как 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 тип, он будет компилироваться, но это не то, что я хочу.