Чи може конструктор std :: vector range викликати явні перетворення?


14

Чи добре сформована наступна програма?

#include <vector>
struct A {
    explicit A(int) {}
};
int main() {
    std::vector<int> vi = {1, 2, 3, 4, 5};
    std::vector<A> va(vi.begin(), vi.end());
}

Відповідно до C ++ 17 [послідовності.рекмтс], вимога до

X u(i, j);

де Xконтейнер послідовності, це:

Tповинні бути EmplaceConstructibleв Xс *i.

Однак у попередньому пункті зазначено, що:

iі jпозначають ітератори, що задовольняють вимогам ітератора вхідних даних і посилаються на елементи, неявно перетворювані на value_type,

Таким чином, мені здається, що обидві вимоги повинні бути дотримані: тип значення діапазону повинен бути неявно перетворюється на тип значення контейнера і EmplaceConstructible повинен бути задоволений (а це означає, що алокатор повинен бути в змозі виконати необхідну ініціалізацію) . Оскільки intвона не піддається неявному перетворенню A, ця програма має бути неправильно сформованою.

Однак, як не дивно, схоже , вона складається в рамках GCC .


(Для запису, це не лише gcc: godbolt.org/z/ULeRDw )
Макс Лангхоф

У цьому випадку не потрібно неявного перетворення, оскільки явний конструктор вже відповідає типу. Я думаю, що опис є заплутаним, але чітка конструкція завжди краще, ніж неявна конверсія перед побудовою.
JHBonarius

Відповіді:


2

Є лише вимога до послідовних контейнерів для підтримки конструкції з ітераторів, які відповідають критеріям неявної конвертованості.

Це само по собі не забороняє контейнери послідовності підтримувати цю конструкцію від ітераторів, які не відповідають цим критеріям, наскільки я можу сказати 1 . Про це існує явне правило:

Якщо конструктор ... викликається з типом InputIterator, який не кваліфікується як вхідний ітератор , конструктор не повинен брати участі у вирішенні перевантаження.

Незрозуміло, що саме "кваліфікувати як ітератор введення" означає саме в контексті. Це неформальний спосіб виразити Cpp17InputIterator, чи він намагається посилатися на вимоги i та j? Не знаю. Дозволено це чи ні, стандарт не має суворої вимоги до його виявлення:

[container.requirements.general]

Поведінка певних функцій члена контейнера та посібників з виведеннями залежить від того, чи класифікуються типи вхідних ітераторів чи розподільників. Ступінь, в якій реалізація визначає, що тип не може бути ітератором введення, не визначено, за винятком того, що як мінімальний інтегральний тип не повинен кваліфікуватися як ітератор введення. ...

З інтерпретацією того, що будь-який Cpp17InputIterator "кваліфікується як ітератор введення", прикладна програма не вимагатиме неправильного формування. Але також не гарантується, що він буде добре сформований.

1 У такому випадку можна вважати проблемою якості впровадження попередження, спираючись на нього. З іншого боку, це обмеження неявних конверсій може вважатися дефектом .


PS Цей компілюється без попереджень у Clang (з libc ++) і Msvc.

PPS Це формулювання, здається, було додано в C ++ 11 (що природно, оскільки тоді також були введені явні конструктори).


1
Дійсно залежить від того, що означає "не кваліфікується як ітератор введення" . В відміну від вище , це на самому ділі не сказати Cpp17InputIterator, так що не ясно для мене чи «і звертатися до елементів неявно , конвертованих в value_type» включений в «вхідний ітератор». Якщо це так, то конструктор не повинен брати участі у вирішенні перевантажень, а програма має бути неправильно сформованою.
Макс Ленгоф

1
Отже, кожному стандартному бібліотечному класу дозволяється мати додаткові конструктори без видачі діагностики, коли ці додаткові конструктори використовуються? Це інтуїтивно мені здається неправильним ...
Брайан

@Brian Я не впевнений, чи є його "зайві конструктори", але, можливо, більше "конкретні реалізації конструкторів, які дозволять отримати більше місця". Перевірка кожного вкладу може мати значний вплив на продуктивність, тому я не знаю, чи це був би шлях ...
JHBonarius

@Brian Це, звичайно, буде поганою ідеєю, навіть якщо явно не заборонено. У цьому випадку ми розглядаємо лише те, чи потрібний конструктор може підтримувати типи ітераторів, які не потрібно підтримувати. У цьому випадку існує чітка вимога "не брати участь", як вказував Макс, що, безумовно, заборонило б це. Але насправді незрозуміло, що саме "кваліфікувати як ітератор введення" означає саме в контексті. Це неофіційний спосіб висловлювати Cpp17InputIteratorчи намагається посилатися на вимоги iта j? Не знаю.
eerorika

2
1) В C ++ встановлюємо низький рівень. . 2) Конструктори - це невіртуючі функції членів . 3) Див. LWG 3297 ; однак я не особливо впевнений, що нам слід зняти неявну вимогу перетворення.
ТК
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.