Почему конструктор копирования не вызывается?
Извините за чрезмерно неоднозначное название (из-за отсутствия моего английского навыка). Пожалуйста, предложите лучшее название.
Пожалуйста, рассмотрите следующий код.
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;