Разрешается ли реализациям добавлять общедоступные члены к стандартным типам?

Разрешено ли реализациям стандартной библиотеки С++ добавлять общедоступные (и защищенные) элементы в интерфейсы стандартных типов? N3797 17.6.5.5 [member.functions]/2 говорит:

Реализация может объявлять дополнительные не виртуальные сигнатуры функций-членов внутри класса:

— путем добавления аргументов со значениями по умолчанию в сигнатуру функции-члена; [ Примечание. Реализация не может добавлять аргументы со значениями по умолчанию в виртуальные, глобальные или функции, не являющиеся членами. — конец примечания ]

— путем замены сигнатуры функции-члена со значениями по умолчанию на две или более сигнатуры функции-члена с эквивалентным поведением; и

— путем добавления подписи функции-члена для имени функции-члена.

Означает ли это, что стандартная библиотека ни при каких обстоятельствах (включая, например, зарезервированные идентификаторы) не может добавлять никаких дополнительных общедоступных членов с именами, не упомянутыми в стандарте?

Небольшое пояснение: это текст о добавлении сигнатур (который, я полагаю, говорит о новых сигнатурах только для функций, которые уже определены, так что никаких новых имен), который мне удалось найти в стандарт. Существует также сноска 189, в которой говорится:

Допустимая программа на C++ всегда вызывает ожидаемую функцию-член библиотеки или функцию с эквивалентным поведением. Реализация также может определять дополнительные функции-члены, которые в противном случае не вызывались бы допустимой программой на C++.

Весь этот текст взят из [member.functions], поэтому он явно касается только функций-членов. Мой вопрос более общий и требует ссылок, которые я мог пропустить: разрешена ли реализация стандартной библиотеки добавлять новые имена в общедоступные (и/или защищенные) интерфейсы стандартного типа, будь то данные или функциональные члены?


person Griwes    schedule 03.02.2014    source источник
comment
Похоже, сноска 189 говорит, что все в порядке ... Однако мне нужно снова проанализировать раздел, чтобы убедиться. Там написано: A valid C++ program always calls the expected library member function, or one with equivalent behavior. An implementation may also define additional member functions that would otherwise not be called by a valid C++ program.   -  person Shafik Yaghmour    schedule 04.02.2014
comment
@ShafikYaghmour, хм, возможно. Однако формулировка, по крайней мере, немного сбивает с толку. Я понимаю, что это формальный текст, но формальные тексты также должны быть написаны так, чтобы их можно было понять, не глядя на них в течение десяти минут.   -  person Griwes    schedule 04.02.2014
comment
Хм, я думаю, разница между подписью и функцией здесь имеет решающее значение, но, вероятно, она где-то скрыта в тексте.   -  person Griwes    schedule 04.02.2014
comment
Вы спрашиваете об общедоступных членах data? Я немного сбит с толку, потому что в процитированном вами абзаце говорится, что он может добавлять членов, а затем вы спрашиваете, означает ли это, что он не может.   -  person Joseph Mansfield    schedule 04.02.2014
comment
Единственный момент, в котором я не уверен, это последний. Остальные довольно просты: не нарушайте код, написанный в соответствии со стандартной совместимой реализацией. Но последний, как указано выше, предлагает только добавить новую подпись (с другими параметрами), а не новое имя?   -  person Mario    schedule 04.02.2014
comment
@JosephMansfield, я спрашиваю о публичных членах. То, что я процитировал в вопросе, - это текст, который я смог найти, и в нем говорится о невиртуальных сигнатурах функций-членов, но вопрос более общий, чем функции или данные-члены. Я, вероятно, должен назвать имена где-то в вопросе.   -  person Griwes    schedule 04.02.2014
comment
Похоже, что 17.6.5.11 Производные классы, вероятно, охватывают то, что вы ищете, это говорит An implementation may derive any class in the C++ standard library from a class with a name reserved to the implementation. и не накладывает никаких ограничений на эти базовые классы. gcc использует это повсеместно, хотя большинство общедоступных элементов данных защищены в классе stl, используя что-то вроде using _Base::_M_impl; в защищенном разделе.   -  person Shafik Yaghmour    schedule 04.02.2014


Ответы (2)


Я считаю, что у вас есть то, что вам нужно, с комбинацией сноски 189, в которой говорится:

Допустимая программа на C++ всегда вызывает ожидаемую функцию-член библиотеки или функцию с эквивалентным поведением. Реализация также может определять дополнительные функции-члены, которые в противном случае не вызывались бы допустимой программой на C++.

и раздел 17.6.5.11 Производные классы, в котором говорится:

Реализация может наследовать любой класс стандартной библиотеки C++ от класса с именем, зарезервированным для реализации.

но не добавляет никаких ограничений, т. е. не ограничивает квалификаторы доступа и т. д.

и мы видим, что libstdc++ довольно эффективно использует производные классы, например, в stl_vector.h. Хотя, насколько я вижу, libstdc++, похоже, избегает добавления общедоступных элементов данных, но это, вероятно, больше для чистого дизайна.

Как минимум, это выглядит недостаточно определенным, но если вы придерживаетесь чего-то похожего на стиль реализации libstdc++, у вас все должно получиться.

person Shafik Yaghmour    schedule 04.02.2014

Я думаю, что ключом к прочтению сноски 189 является фраза would otherwise not be called by a valid C++ program.

Помните, что идентификаторы, начинающиеся со знака подчеркивания, за которым следует заглавная буква (или содержащие два последовательных знака подчеркивания в любом месте), зарезервированы для реализации. (раздел 17.6.4.3.2)

Таким образом, реализации могут свободно добавлять общедоступные/защищенные функции-члены, названные таким образом.

Например, в libc++ std::vector имеет защищенную функцию-член с именем __throw_length_error.

person Marshall Clow    schedule 04.02.2014