Идеальная пересылка в конструкторах (C ++ 17) - PullRequest
0 голосов
/ 28 ноября 2018

Рассмотрим следующий код

struct A {
    A(int id) : id_ { id } {}

    A(const A& rhs) { std::cout << "cctor from " +
        std::to_string(rhs.id_) << std::endl; }
    A(A&& rhs) { std::cout << "mctor from " +
        std::to_string(rhs.id_) << std::endl; }

    int id_;
};

template<typename T>
struct B1 {
    constexpr B1(T&& x) noexcept : x_ { std::forward<T>(x) } {}

    T x_;
};

template<typename T>
struct B2 {
    constexpr B2(T&& x) noexcept;

    T x_;
};

template<typename T>
constexpr
B2<T>::B2(
    T&& x
) noexcept :
    x_ { std::forward<T>(x) } {
}

int
main(
) {
    A a { 1 };

    //B1 b11 { a }; // Not compiling
    B1 b12 { A { 2 } };

    B2 b21 { a };
    B2 b22 { A { 3 } };

    return 0;
 }

, который дает

mctor from 2
mctor from 3

Таким образом, в общем случае выглядит так, как будто внешне определенный конструктор прекрасно перенаправляет категорию значения своего аргумента, в то время как встроенныйне конструктор.

Это то, что внешне определенный конструктор обрабатывается как шаблон функции (который прекрасно передает свои аргументы) или что здесь происходит?

Ссылки на соответствующий раздел стандартабудет приветствоваться.

Я использую GCC 7.2.0.

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Похоже, что GCC неправильно обрабатывает T&& в автоматически сгенерированном руководстве по вычетам как ссылку для пересылки:

template <typename T>
B2(T&& x) -> B2<T>;

В этом случае T&& - это ссылка на неопределяемое значение r, потому чтоэто параметр класса.Вместо этого GCC неправильно выводит T=A& тип параметра и B2<T>=B2<A&> тип класса, который сворачивает ссылочный тип в конструкторе, позволяя коду компилироваться с аргументом конструктора lvalue:

constexpr B2(A& x) noexcept;

Вывод аргумента шаблона классане делает различий между встроенными и внешними определениями.В этом конкретном случае B2 b21 { a }; должен завершиться неудачей.

0 голосов
/ 28 ноября 2018

Это ошибка GCC.Пересылочные ссылки имеют очень четкое определение:

[temp.deduct.call] (выделено)

3 A ссылка на переадресацию - это rvalue ссылка на неквалифицированный cv параметр шаблона , который не представляет параметр шаблона шаблона класса (во время вывода аргумента шаблона класса ([over.match.class.deduct])).Если P является ссылкой для пересылки, а аргумент является lvalue, тип «lvalue ссылка на A» используется вместо A для вывода типа.

В обоих случаях T называет параметр шаблонакласса включения во время CTAD, поэтому он не должен создавать ссылку для пересылки в любом случае.C'or, определяемый внутри или вне определения класса, не имеет к этому никакого отношения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...