перегрузка шаблона приводит к ошибке компоновщика / странному поведению - PullRequest
0 голосов
/ 16 октября 2018

со следующим минимальным примером я получаю ошибку компоновщика в моей локальной системе в Visual Studio 15.8.7 (стандартное консольное приложение со стандартными настройками (только что удалены предварительно скомпилированные заголовки)): «Ошибка LNK1179 неверный или поврежденный файл: дубликат COMDAT '?? $ f @ H @@ YAXH @ Z '"

#include <cstdio>
template<typename T> void f(T) { printf("1"); }  //#1. T can be deduced
template<typename T> void f(int) { printf("2"); } // #2. T needs to be specified explicitly

int main()
{
    f(8); // a) calls #1
    f<int>(8); // b) calls #2           
}
  • Комментирование вызова a) или вызова b) приведет к успешному соединению.Автономный вызов а) вызывает шаблон определения # 1.Второй вызов б) вызывает определение шаблона №2.Как и ожидалось.
  • Построение в режиме выпуска завершено успешно.Выходное значение равно 11. Таким образом, оба вызова вызывают определение шаблона № 1.Неожиданный. ODR-нарушение?
  • Кроме того, я заметил следующее странное поведение (в настройках отладки):
    1. я закомментирую определение шаблона # 2
    2. я делаюполная перестройка
    3. я комментирую в определении шаблона # 2
    4. я собираю (не перестраиваю, просто собираю)
    5. сборка завершается
    6. вместо этого выводится 11из 12

Инкрементное связывание, делающее странные вещи?

На wandbox, godbolt и coliru я могу скомпилировать, связать, запустить и получитьожидаемое поведение с gcc и clang.

Наблюдения, описанные в пуле 3, заставили меня подумать, что это связано с добавочной связью.Но, может быть, код тоже не очень хорошо определен?При изучении https://en.cppreference.com/w/cpp/language/function_template я обнаружил следующее:

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

и

Если программа содержит объявления шаблонов функций, которые функционально эквивалентны, но не эквивалентны, программа является некорректной;Диагностика не требуется.

Итак, код выше не сформирован?Есть ли у меня нарушение ODR?Или все нормально, и это просто ошибка компоновщика / компилятора?

edit: фиксированная точка 3. Я комментирую в определении # 2 или курсе.

Обновление: Новоедень, проблемы решены, я думаю.Сегодня я не могу воспроизвести проблему.Я ничего не изменил в моей системе.Я только загрузился, открыл свой проект, и он работал как ожидалось.Не знаю, что происходит.Но так лучше по сравнению с изучением новых специальных правил перегрузки тайных шаблонов: -P

1 Ответ

0 голосов
/ 16 октября 2018

Программа в порядке.У вас есть две разные функции, которые вызываются.Это ошибка компилятора и / или компоновщика.

[temp.over.link] приводит к:

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

[Пример:

// translation unit 1:
template<class T>
  void f(T*);
void g(int* p) {
  f(p); // calls f<int>(int*)
}

// translation unit 2:
template<class T>
  void f(T);
void h(int* p) {
  f(p); // calls f<int*>(int*)
}

- конец примера]

Такие специализации являются различными функциями и не нарушаютПравило одного определения.

У вас есть два разных шаблона функций, полная остановка.Формулировка об эквивалентности имеет отношение к параметрам шаблона и зависимым выражениям ( [temp.over.link] / 5 ):

Два выражения , включающие параметры шаблона считаются эквивалентными, если [...]

int не содержит параметр шаблона, поэтому его никоим образом нельзя считать эквивалентным T.

...