Помните, что класс - друг сам по себе:
v3(const v3<T> & v)
{
_a[0] = v._a[0];
_a[1] = v._a[1];
_a[2] = v._a[2];
}
Когда вы копируете что-то того же типа, вы уже знакомы с деталями реализации. Таким образом, нет проблем с непосредственным доступом к реализации, если это уместно. Таким образом, из конструктора вы можете получить доступ к объекту, который копируете напрямую, и увидеть его член '_a'.
Если вы хотите узнать исходную проблему:
Литерал '1' в контексте 'v [1]' является целым числом (это синоним целого числа со знаком). Таким образом, чтобы использовать оператор [], технически компилятор должен вставить преобразование из int в unisgned. Другая альтернатива - использовать оператор * (), чтобы получить указатель на внутренний объект, а затем использовать оператор [] для указателя. Компилятору не разрешается делать этот выбор и выдавать ошибку:
Параметры компилятора:
_a[1] = v[1];
// Options 1:
_a[1] = v.operator[]((unsigned int)1);
// Options 2:
_a[1] = v.operator*()[1];
Чтобы сделать его невидимым, вы можете использовать беззнаковый литерал;
_a[1] = v[1u];
В долгосрочной перспективе, возможно, стоит сделать это проще для пользователя.
Преобразуйте оператор [], чтобы использовать int вместо unsigned int, тогда вы получите точное совпадение, когда целочисленные литералы (или вы можете иметь два набора оператора []. Один использует int, а другой использует unsigned int).