указатель на функцию и ODR

Есть много вопросов по ODR, но я не могу найти то, что ищу, поэтому извиняюсь, если это дубликат или название неуместно.

Учтите следующее:

struct t {t(*id)();};

template<typename T>
t type() {return {type<T>};}

Это чрезмерное упрощение моей попытки определить уникальный идентификатор для каждого типа, мы надеемся, что он остается уникальным для разных модулей компиляции.

В частности, учитывая конкретный тип T лайк std::stringи, предполагая, что два различных блока компиляции включают в себя код выше в заголовочном файле, я хотел бы выражение

type<T>().id

принять одинаковое значение (типа t(*)()) в обеих единицах, следовательно, служат уникальным идентификатором для типа T,

Значение является адресом функции type<T>, поэтому вопрос в том, является ли уникальная функция type<T> в программа гарантируется правило одного определения. ISO 3.2 / 3 говорит

Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, используемой в этой программе.

где по 3,2 / 2

Неперегруженная функция, имя которой появляется в качестве потенциально вычисляемого выражения или […], используется odr, если […]

и я предполагаю, что функция не является встроенной, если ее адрес взят (хотя я не могу найти это в стандарте).

ISO 3.2 / 5 перечисляет ряд исключений, но единственные ссылки на функции

встроенная функция с внешней связью, […], нестатический шаблон функции, […], функция-член шаблона класса или специализация шаблона, для которой не указаны некоторые параметры шаблона […]

и ни один, кажется, не имеет место здесь.

Поддающийся проверке пример может занять более одного файла. На самом деле, пример, заявленный как провал, дается Дитер Люкинг, хотя это не терпит неудачу в моем случае (который я не принимаю как любую форму «гарантии»).

Так это сработает или нет?

7

Решение

Так что 3.2 / 5 на самом деле кажется довольно сильной поддержкой. Прежде всего обратите внимание, что определение является конструкцией исходного кода, а не конструкцией объектного кода, хотя очевидно, что существует очень тесная связь. 3.2 / 5 говорит, что можно иметь несколько определений шаблонов нестатических функций, и, кроме того, в таком случае оно должно вести себя так, как если бы было только одно определение. Если функция имела разные адреса в разных единицах перевода, то это не ведет себя так, как если бы было только одно определение, по крайней мере, в моем чтении.

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

Будут ли выполнены все требования, будет зависеть в точности от контекста нескольких определений, поскольку они имеют дело с такими вещами, как разрешение имен и т. Д. Однако все они являются «заурядными» требованиями, которые типа «конечно». Например, нарушение было бы что-то вроде:

file1.cpp

static int i;

// This is your template.
template <typename T>
void foo() {
i; // Matches the above i.
}

file2.cpp

static int i;

// This is your template. You are normally allowed to have multiple
// identical definitions of it.
template <typename T>
void foo() {
// Oops, matches a different entity. You didn't satisfy the requirements.
// All bets are off.
i;
}

Я знаю, что множественные определения поддерживаются в Linux через слабые символы. На самом деле, в Linux пример Lucking не может провалиться именно из-за этого. Я оставил комментарий к его ответу с просьбой о платформе. Во время ссылки компоновщик отбрасывает все экземпляры слабого символа, кроме одного. Очевидно, что если экземпляры на самом деле не совпадают, это было бы плохо. Но эти требования в 3.2 / 5 предназначены для того, чтобы гарантировать, что экземпляры фактически все одинаковы, и, следовательно, компоновщик может оставить только один.

ДОБАВЛЕНИЕ: Дитер Лакинг теперь говорит, что у него была проблема с компиляцией, и это на самом деле для него не проблема. Было бы хорошо, если бы кто-то, знакомый с внутренними компонентами Windows DLL, мог прокомментировать здесь, как Visual Studio справляется с этим.

4

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


По вопросам рекламы [email protected]