Информация об изменениях

Сообщение Инжектирование друзей класса в охватывающее пространство име от 10.01.2022 19:55

Изменено 10.01.2022 20:16 Андрей Тарасевич

Инжектирование друзей класса в охватывающее пространство имен
Пусть у нас есть такое определение шаблона класса

template <typename T> struct S
{
  friend void foo()
  {
    std::cout << "Hello World" << std::endl;
  }
  
  friend void bar()
  {
    T t{};
    std::cout << t << std::endl;
  }
};


Если я попытаюсь инстанцировать такой шаблон для двух разных типов `T` в одной единице трансляции, я сразу получу от компилятора сообщение об ошибке из-за множественного определения функций `foo` и `bar`. Например

int main()
{
  S<int> a;
  S<double> b;
}


In instantiation of 'struct S<double>':
error: redefinition of 'void foo()'
    5 |   friend void foo()
      |               ^~~
main.cpp:10:15: error: redefinition of 'void bar()'
   10 |   friend void bar()
      |               ^~~


Это понятно.

Но что произойдет, если я сделаю два разных инстанцирования этого шаблона в разных единицах трансляции?

Обратите внимание, что `foo` и `bar` являются не шаблонными (template), но "шаблонизированными" (templated) inline-функциями. При этом я специально сделал определение `foo` не зависящим от параметра шаблона `T`, а определение `bar` — явно зависящим от параметра шаблона.

Я бы предположил, что определения `foo` в разных единицах трансляции соответствуют всем требованиям, налагаемым на определения inline-функций, то есть с `foo` все в порядке. А вот `bar`, из-за ее зависимости от `T`, нарушает эти требования. Соответственно на `bar` я буду иметь нарушение ODR, скорее всего с "no diagnostic required".

Правильны ли мои предположения?
Инжектирование друзей класса в охватывающее пространство име
Пусть у нас есть такое определение шаблона класса

template <typename T> struct S
{
  friend void foo()
  {
    std::cout << "Hello World" << std::endl;
  }
  
  friend void bar()
  {
    T t{};
    std::cout << t << std::endl;
  }
};


Если я попытаюсь инстанцировать такой шаблон для двух разных типов `T` в одной единице трансляции, я сразу получу от компилятора сообщение об ошибке из-за множественного определения функций `foo` и `bar`. Например

int main()
{
  S<int> a;
  S<double> b;
}


In instantiation of 'struct S<double>':
error: redefinition of 'void foo()'
    5 |   friend void foo()
      |               ^~~
main.cpp:10:15: error: redefinition of 'void bar()'
   10 |   friend void bar()
      |               ^~~


Это понятно.

Но что произойдет, если я сделаю два разных инстанцирования этого шаблона в разных единицах трансляции?

Обратите внимание, что `foo` и `bar` являются не шаблонными (template), но "шаблонизированными" (templated) inline-функциями. При этом я специально сделал определение `foo` не зависящим от параметра шаблона `T`, а определение `bar` — явно зависящим от параметра шаблона.

Я бы предположил, что определения `foo` в разных единицах трансляции соответствуют всем требованиям, налагаемым на определения inline-функций, то есть с `foo` все в порядке. А вот `bar`, из-за ее зависимости от `T`, нарушает эти требования. Соответственно на `bar` я буду иметь нарушение ODR, скорее всего с "no diagnostic required".

Правильны ли мои предположения?