Почему конструктор копирования не вызывается?

Извините за чрезмерно неоднозначное название (из-за отсутствия моего английского навыка). Пожалуйста, предложите лучшее название.

Пожалуйста, рассмотрите следующий код.

struct A {
    typedef std::vector<double> State;

    //  template <class... Args>
    //  A(Args... args)
    //      : a(args...)
    //  {}

    template <class... Args>
    A(Args&&... args)
            : a(std::forward<Args>(args)...)
    {}

    A(const A&) = default;
    A(A&&) = default;

    State a;
};

int main(){

    A a(3,2);
    A b = a; // This line triggers an error!!
}

Gcc 4.8.0 не удалось скомпилировать его с сообщением об ошибке error: no matching function for call to 'std::vector<double>::vector(A&)' : a(std::forward<Args>(args)...).

Я не могу понять, почему этот код неправильный. На мой взгляд, компилятор должен вызвать конструктор копирования в строке A b = a;.

Однако, если я заменил конструктор на комментарий (который просто принимает значения). Он компилируется. Кроме того, теперь строки для конструкторов копирования (и перемещения) по умолчанию не нужны. Что здесь происходит?

Ответ 1

В С++ 11, когда компилятор автоматически выводит параметры шаблона (как вы должны делать с шаблонизированным конструктором) и применяя && к типу, создается универсальная ссылка, которая соответствует любому типу с любой квалификацией cv, независимо от того, lvalue или rvalue.

Итак, в вашем случае вы передаете A и, следовательно, Args...= A &, Args &&...= A & &&, который равен A & благодаря правилам смены ссылок, которые являются лучше, чем const A &, поскольку компилятору не нужно добавлять константу к неконстантной переменной.

Ответ 2

Я думаю, что в этом случае конструктор шаблонов лучше сочетается, потому что он принимает неконстантное значение. если вы измените a на const, он вызовет конструктор копирования...

const A a(3,2);
A b = a;