Неявные специальные функции: когда они будут плохо сформированы?
В Международном стандарте ISO для c++ 11 приводится краткое изложение различий между c++ 2003 и c++ 2011. Одно из отличий:
[Diff.cpp03.special]
Изменение. Неявно объявленные специальные функции-члены определяются как удаленные, если неявное определение было бы плохо сформировано.
Обоснование: улучшает сбой вывода аргумента шаблона.
Влияние на оригинальную функцию: действующая программа c++ 2003, которая использует одну из этих специальных функций-членов в контексте, в котором определение не требуется (например, в выражении, которое потенциально не оценивается), становится плохо сформированным.
Я не вижу, в каком состоянии такие специальные функции будут плохо сформированы и как это может сломать SFINAE. Поэтому мой вопрос сводится к следующему:
- Почему такое изменение "улучшает сбой вывода аргумента шаблона"?
- Не могли бы вы привести пример?
Ответы
Ответ 1
struct NonCopyable {
NonCopyable() {}
private:
NonCopyable(const NonCopyable &);
};
struct S {
NonCopyable field;
} s;
int main() {
return sizeof S(s);
}
Здесь NonCopyable
не копируется, но поскольку конструктор копирования явно указан, конструктор неявной копии не создается.
Для S
никакой конструктор копирования не предоставляется пользователем, поэтому создается неявный конструктор копирования. Этот конструктор копии NonCopyable
field
поля NonCopyable
, которое не копируется, поэтому конструктор копирования будет плохо сформирован.
В main
берется размер объекта S
построенного на копирование. Для этого требуется конструктор копирования S
, но на самом деле его не называет.
В С++ 03 это действительно. Конструктор копирования будет плохо сформирован, но поскольку никакой копии не было сделано, все в порядке.
В С++ 11 это недопустимо. Конструктор копирования помечен как удаленный, поэтому его нельзя использовать даже в качестве операнда для sizeof
.
Это позволяет метапрограммировать, можно ли копировать этот тип, что было невозможно в С++ 03.
Ответ 2
Если вам нужен конкретный пример, std :: pair, как правило, очень легко копировать, но если один из членов, скажем, std :: unique_ptr, unique_ptr не позволяет копировать из Lvalue, значит, он будет плохо сформирован: поэтому операции копирования по умолчанию std :: pair по умолчанию автоматически удаляются.