Не нарушают ли множественные определения объекта лямбда-выражения в разных единицах перевода ODR в C ++?

Я думал, что следующие коды нарушает ODR (f определяется как в foo.cpp, так и в main.cpp), но компилятор не выдает ошибки.

// foo.h
auto f = [](int i){return i;};
void printTypeID();

// foo.cpp
#include "foo.h"#include <typeinfo>
#include <iostream>

void printTypeID(){
std::cout << typeid(f).name() << '\n';
}

// main.cpp
#include "foo.h"#include <typeinfo>
#include <iostream>

int main(){
std::cout << typeid(f).name() << '\n';
printTypeID();
return 0;
}

И выходной typeid идентичен, что меня удивляет, потому что я думал, что каждое лямбда-выражение будет иметь уникальный тип класса, не являющийся объединением, если только он не находится в теле определения внешней встроенной функции.


Редактировать: Поскольку я изучаю стандарт, я намерен думать, что это потому, что объекты безымянного типа имеют внутреннюю связь. Хотя я не нашел соответствующей спецификации. Это связанные спецификации, которые я нашел ниже.

Тип лямбда-выражения является уникальным неименованным типом класса, не являющимся объединением: expr.prim.lambda

Тип лямбда-выражения (который также является типом объекта замыкания) является уникальным, безымянный несоюзный класс Тип — называется тип закрытия — свойства которого описаны ниже. […]

Безымянный тип класса, имеющий глобальную область видимости, не имеет связи, но тип без связи все еще может использоваться для объявления объекта с внешней связью. basic.link

Имена, на которые не распространяются эти правила, не имеют связи. Кроме того, за исключением отмеченного, имя, объявленное в области видимости блока ([basic.scope.block]), не имеет связи. тип Говорят, что есть связь если и только если:

  • это тип класса или перечисления, который назван (или имеет имя для целей связывания ([dcl.typedef])), а имя имеет связь; или же
  • это неназванный класс или перечисление без имени, которое является членом класса со связью; или же
  • это специализация шаблона класса (Clause [temp]) 34; или же
  • это фундаментальный тип ([basic.fundamental]); или же
  • это составной тип ([basic.compound]), отличный от класса или перечисления, составленный исключительно из типов, имеющих связь; или же
  • это cv-квалифицированная ([basic.type.qualifier]) версия типа, имеющая связь.

Тип без связи не должен использоваться в качестве типа переменной или функции с внешней связью, если только

  • у объекта есть связь языка C ([dcl.link]), или
  • объект объявляется в безымянном пространстве имен ([namespace.def]), или
  • сущность не используется odr ([basic.def.odr]) или определяется в той же единице перевода.

И объект лямбда-выражения (f в этом случае) НЕ является переменной, которая имеет внутреннюю связь в соответствии со следующими цитатами: basic.link

Имя с областью пространства имен ([basic.scope.namespace]) имеет внутреннюю связь, если это имя

  • переменная, функция или шаблон функции, которые явно объявлены статическими; или же,
  • не встроенная переменная энергонезависимого константно-квалифицированного типа, который явно не объявлен как extern или ранее не объявлен как имеющий внешнюю связь; или же
  • член данных анонимного союза.

Пространство имен без имени или пространство имен, объявленное прямо или косвенно в пространстве имен без имени, имеет внутреннюю связь. Все остальные пространства имен имеют внешнюю связь. Имя, имеющее область пространства имен, которому не была дана внутренняя связь выше, имеет ту же связь, что и окружающее пространство имен, если это имя […]

Таким образом, выходные идентификаторы типов в предыдущих кодах могут быть идентичны, и здесь это не проблема, так как тип замыкания в этом случае не имеет связи. Но возникает вопрос:

Есть ли у объектов безымянного типа класса, имеющих глобальную область видимости, внутреннюю связь?

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector