Рассмотрим следующий код:
#include <type_traits>
template<typename T>
struct A1 {
T t;
// implicitly-declared default constructor
};
template<typename T>
struct A2 {
T t;
// explicitly-declared default constructor without noexcept
A2() = default;
};
template<typename T>
struct A3 {
T t;
// explicitly-declared default constructor with noexcept
A3() noexcept(std::is_nothrow_default_constructible<T>::value) = default;
};
Эквивалентны ли эти три конструктора по умолчанию в C++?
Эквивалентны ли эти три конструктора по умолчанию в C++?
Да, векторы по умолчанию эквивалентны в контексте noexcept specification
.
Это можно увидеть из default ctor:
Неявно объявленный (или заданный по умолчанию при первом объявлении) конструктор по умолчанию имеет спецификацию исключения, как описано в спецификации динамического исключения (до C++17) и спецификации noException (начиная с C++17).
Итак, мы переходим к спецификации noException:
Каждая функция в C++ либо не выбрасывает, либо потенциально выбрасывает:
- потенциально выбрасывающие функции:
- функции, объявленные без спецификатора noException, за исключением
- конструкторы по умолчанию, конструкторы копирования, конструкторы перемещения, которые объявлены неявно или по умолчанию при первом объявлении, если только
- конструктор для базы или члена, который будет вызывать неявное определение конструктора, потенциально выбрасывает (см. ниже)
Я думаю, независимо от того, является ли std::is_nothrow_default_constructible<T>::value
true
или false
, эти три вектора по умолчанию кажутся эквивалентными.
@xmllmx Источник?
Просто моя интуиция: если ctor по умолчанию T
потенциально выбрасывает, то A1()
& A2()
тоже потенциально выбрасывает; в противном случае, если ctor по умолчанию не генерирует генерацию, то T
и A1()
также должны быть негенерирующими. Итак, я думаю, что эти три должны быть эквивалентны.
@user12002570 user12002570, вы не заключили в кавычки текст после <<unless>>: «конструктор для базы или члена, который будет вызывать неявное определение конструктора, потенциально выбрасывает (см. ниже)». Итак, я бы сказал, что все три конструктора имеют одну и ту же подпись (С++ 17 и более поздние версии)?
@xmllmx Другими словами, noexcept(std::is_nothrow_default_constructible<T>::value)
не имеет права голоса при принятии решения о том, бросается ли это или нет? Я также вижу фразу «специальные функции-члены по умолчанию» в последней цитируемой ссылке в моем ответе. Таким образом, эти три кажутся эквивалентными.
@user12002570 user12002570, я думаю, если ctor по умолчанию T
потенциально выдает ошибку, то std::is_nothrow_default_constructible<T>::value
должно быть false
; иначе true
.
«Я думаю, что если ctor по умолчанию T потенциально выбрасывает, то std::is_nothrow_default_constructible<T>::value должно быть ложным; в противном случае — true». Это ложь.
«Просто моя интуиция: если ctor по умолчанию T потенциально выбрасывает, то A1() и A2() также должны быть потенциально выбрасывающими; в противном случае, если ctor по умолчанию T не выбрасывает, тогда A1() и A2() также должны быть невыбрасывающими. - бросание». У A1 нет конструктора, являющегося агрегатом. И, как уже упоминалось, «потенциально выбрасываемый по умолчанию ctor T» — это не (только) то, что тестирует признак типа.
Два и три эквивалентны; три просто подвержены ошибкам и избыточны.
Первый эквивалентен с точки зрения функциональности конструктора. Однако, поскольку у нее нет явно объявленного (даже заданного по умолчанию) конструктора, структура является агрегатом, в отличие от двух других.
Вопрос в noexcept specification
. Я не понимаю, как это авторитетно отвечает на вопрос.
@Алан Вы имеете в виду, что ожидаете цитат из стандарта, подтверждающих мое утверждение?
Вопрос в том, эквивалентны ли они не только в noException?
@JeffGarrett Насколько я понимаю, вопрос заключается в том, эквивалентны ли ctors в контексте спецификации noException, а не в том, является ли он агрегатным или нет, или как инициализировать объект этого типа и т. д.
Справедливо. Наверное, я прочитал это по-другому. Я вижу «эквивалентны ли эти конструкторы» (в заголовке и выделено жирным шрифтом в теле), и нет никаких вопросов о том, эквивалентны ли они относительно noException или любого другого конкретного фактора.
@user12002570 user12002570 Я не читал это таким образом, но тот факт, что ваш ответ принят, предполагает, что вы лучше угадаете намерения ОП.
Ничто из этого не эквивалентно друг другу.
Во-первых, A1<T>
является совокупностью , тогда как A2<T>
и A3<T>
таковыми не являются. См. богболт. Определение агрегата различается в разных стандартах, и это агрегат (опять же) в C++20... поэтому, если вы поддерживаете старые стандарты, A1<T>
будет иметь очень разные возможности в каждом из них.
Это оказывает сильное влияние на то, где и как они могут быть построены. Если можно построить T
, можно построить A1<T>
, но не обязательно A2<T>
или A3<T>
. См. богболт .
Итак, A1<T>
отличается от других тем, сможете ли вы вообще его построить.
A2<T>
и A3<T>
различаются тем, является ли конструктор по умолчанию noexcept
. std::is_nothrow_default_constructible_v
не проверяет, является ли значение не только конструируемым, но и разрушаемым. В то время как объявление по умолчанию без спецификации noException проверяет только конструкторы. См. богболт . (Это LWG 2116.)
Первые два эквивалентны описанию здесь. Спецификация третьего исключения зависит от того, имеет ли выражение значение true или нет.