4

Возьмут следующий код:Передвижение оператора присваивания авто сгенерированного (VS ошибки?)

class Foo 
{ 
    Foo const& operator =(Foo const& rhs); // disallow 
}; 

struct Bar 
{ 
public: 
    Foo foo; 

    template <class T> 
    T const& operator =(T const& rhs) { return rhs; } 
}; 

struct Baz : public Bar { 
    using Bar::operator =; 
}; 

int main() 
{ 
    Baz b1, b2; 
    b1 = b2; 
} 

Это не может компилироваться, так как оператор присваивания автоматически сгенерированными для бара :: оператора = будет использоваться, который пытается использовать Foo :: operator =, который является приватным. Хорошо. Таким образом, я добавил в дополнительный элемент к бару:

Bar const& operator =(Bar const& b) { return Bar::operator=<Bar>(b); } 

Теперь у нас другая проблема. У меня две перегрузки, только одна из которых может быть использована. Я проезжаю в Baz const &. Все, что я знаю о C++, говорит о том, что это должно закончиться использованием версии без шаблонов, потому что сначала выбираются совпадающие не-шаблоны. Это также похоже на то, что делает gcc. Visual Studio, кажется, не согласен:

error C2666: 'Bar::operator =' : 2 overloads have similar conversions 
    could be 'const Bar &Bar::operator =(const Bar &)' 
    or  'const T &Bar::operator =<Baz>(const T &)' 
    with 
    [ 
     T=Baz 
    ] 
    while trying to match the argument list '(Baz, Baz)' 

Я искушение верить GCC здесь, и потому, что мое понимание C++ подтверждает это, и потому, что я вообще сторона с НКОЙ, когда он не согласен с Visual Studio, но я не что я об этом беспокоюсь:

В моем не минимальном примере я, честно говоря, не нуждаюсь в том, что оператор присваивания по умолчанию вообще не нужен. Я был бы более чем счастлив, если оператор шаблона выполнит работу - он сделает это правильно. Однако, поскольку VS жалуется на конфликт между шаблоном и автоматически сгенерированным оператором присваивания, я не могу заставить этот шаблон работать вообще. Я пробовал все следующие:

  1. Выполнение оператора присваивания приватным и невыполненным (не работает, потому что «не все Перегрузки acecssible»)
  2. Создание его (что приводит к указанной выше ошибки)
  3. Оставив его (что приводит к ошибке выше оператора присваивания по умолчанию сгенерированные)
  4. Создание специализации шаблона для этого типа, таким образом, соответствующий оператор назначения по умолчанию точно (явно незаконным в соответствии с компилятором)

У кого-нибудь есть яркие идеи о том, как я могу обойти эту проблему? К сожалению, моя версия VS не поддерживает переопределение C++ 0x «delete» оператора автогенерированного присваивания, поэтому это не вариант, и я не могу думать о других способах обойти эту ошибку.

+0

Зачем вам нужна эта конструкция вообще? Если у вас есть причина объявить класс нецелесообразным, почему вы должны сделать дочерний присваиваемый – Martin

+1

@Martin, это пример минимального воспроизведения. Фактический вариант использования намного сложнее и включает метапрограммирование шаблонов, которое не имеет отношения к вопросу. – Shirik

+0

Возможно, я ошибаюсь: может ли возникнуть проблема со строительством? Обычно оператор = возвращает & для цепочки. Возможно, VS показывает какое-то странное поведение в этом направлении. – Martin

ответ

2

Неопределенность, возникающая при разрешении между двумя версиями оператора присваивания, вызвана использованием «use Bar :: operator =» в определении Baz.

Неявный или явно определенный в Bar, версия без шаблона принимает аргумент «const Bar &», который точно не соответствует «Baz», как это требуется для однозначного разрешения по сравнению с шаблоном.

Существует много способов обойти это, но реальное решение будет зависеть от реального источника.

Чтобы исправить пример, я хотел бы сделать эти вещи:

уплотнительных Предотвратить автоматическую генерацию const Bar& operator =(const Bar& b), потому что он будет использовать оператор присваивания Foo в.То, что вы уже пытались добавить к определению Бара будет работать:

Bar const& operator =(Bar const& b) { 
    return Bar::operator=<Bar>(b); 
} 

using Bar::operator = уплотнительного в определении Баз должен идти. Замените его функцией, которая обертывает Bar :: operator =. Такие, как:

template <class T> 
const T& operator =(const T& rhs) { 
    return Bar::operator =(rhs); 
} 

(Конечно, не напуганный код будет всегда возвращать * это - Бар &, а не типом аргумента.)

+0

У меня была аналогичная проблема, и это решение сработало для меня. Возможно, это не сработало для OP (поскольку оно не отмечено как правильно), но это стоит того. Я тоже на VS, и это похоже на ошибку VS и является обходным решением. – Samaursa

Смежные вопросы