Адреса идентичных экземпляров шаблонов функций в единицах компиляции - PullRequest
7 голосов
/ 06 октября 2011

Почему это работает?

Я вижу похожие вопросы о том, что это так, но может кто-нибудь объяснить это более подробно? В частности, защищено ли это поведение стандартом?

i.h

#ifndef I_H_
#define I_H_

typedef void (*FuncPtr)();

template<typename T>
void FuncTemplate() {}

class C {};

#endif

a.cc

#include "i.h"

FuncPtr a() {
  return &FuncTemplate<C>;
}

b.cc

#include "i.h"

FuncPtr b() {
  return &FuncTemplate<C>;
}

m.cc

#include <iostream>

#include "i.h"

FuncPtr a();
FuncPtr b();

int main() {
  std::cout << (a() == b() ? "equal" : "not equal") << std::endl;

  return 0;
}

Тогда

$ g++ -c -o a.o a.cc
$ g++ -c -o b.o b.cc
$ g++ -c -o m.o m.cc
$ g++ a.o b.o m.o -o prog
$ ./prog
equal

Вбрасывание -Wall -Wextra -Werror -ansi на все вызовы g++ производит то же самое.

Мое (наивное) понимание состоит в том, что FuncTemplate создается один раз в каждом из блоков компиляции a.o и b.o, и поэтому каждый адрес должен указывать на одну копию. Как они в конце концов остаются одинаковыми, и это поведение переносимо или защищено?

РЕДАКТИРОВАТЬ Корпус общей библиотеки:

$ g++ -shared -o liba.so a.cc
$ g++ -shared -o libb.so b.cc
$ g++ -c -o m.o m.cc
$ g++ -L. -la -lb m.o -o prog
$ ./prog
equal

Ответы [ 2 ]

6 голосов
/ 06 октября 2011

Подпадает под одно правило определения:

3.2 Одно правило определения [basic.def.odr]

Пункт 5:

Может быть несколько определений типа класса (раздел 9), типа перечисления (7.2), встроенной функции с внешней связью (7.1.2), шаблона класса (раздел 14), нестатическая функция template (14.5.6) , статический член данных шаблона класса (14.5.1.3), функция-член шаблона класса (14.5.1.1) или специализация шаблона, для которой не указаны некоторые параметры шаблона (14.7, 14.5) .5) в программе при условии, что каждое определение появляется в другой единице перевода, и при условии, что определения удовлетворяют следующим требованиям. Если такая сущность с именем D определена более чем в одной единице перевода, то

Существует целый список критериев, которым необходимо следовать, или их неопределенному поведению. В вышеупомянутом они действительно держатся. Тогда ...

Если определения D удовлетворяют всем этим требованиям, то программа должна вести себя так, как если бы было одно определение D.

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

Похоже, что формулировка в последней фразе требует, чтобы все они вели себя одинаково. Это означает, что получение адреса любого из этих объектов должно привести к тому же адресу.

4 голосов
/ 06 октября 2011

Это гарантируется стандартом, поскольку оно не нарушает одно определение правила. По сути, если объявление и определение встроенной функции или шаблонной функции одинаковы в нескольких единицах перевода, программа должна вести себя так, как будто существует одно ее определение, которое распространяется на ее адрес, когда оно принято. См. Мой ответ на другой вопрос, который касается статических членов шаблонных классов.

Что касается соответствующего раздела стандарта [basic.def.odr]:

... Если определения D удовлетворяют всем этим требованиям, то Программа должна вести себя так, как если бы было одно определение D. Если определения D не удовлетворяют этим требованиям, то поведение не определено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...