Почему мне нужна связь C ++ для шаблона?

0

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

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

Итак, почему этот код не компилируется (я использую С++ 11 с gcc и clang в данный момент, но я не думаю, что это уместно в этом случае)?

#include <iostream>
#include <cstdint>
#include <cstdlib>
extern "C" {
template <typename T>
T foo(T t)
{
    return t;
}
}
int main()
{
    uint32_t a = 42;
    std::cout << foo(a) << '\n';
    return EXIT_SUCCESS;
}

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

Какова техническая причина, по которой этот код не компилируется?

  • 0
    @crashmstr Я не знаю, что вы пробовали, но extern "C" влияет на фазу линковки, не совсем то, что "работает или нет", это то, что стандарт говорит о extern , также код внутри extern который все еще компилируется с Компилятор C ++.
  • 2
    Связанный с шаблоном External Linkage? Может кто-нибудь объяснить это?
Теги:
c++11
extern

3 ответа

14
Лучший ответ

Давайте посмотрим на это с простой точки зрения. По крайней мере, использование extern "C" приведет к удалению имени C++. Итак, у нас есть ваш шаблон, и мы будем создавать его дважды.

int foo(int val);
float foo(float val);

В соответствии с правилами именования C они должны иметь одно и то же имя foo с точки зрения компоновщика. Если они имеют одно и то же имя, мы не можем различать их, и у нас будет ошибка.

В C++ правила для того, как имена искажаются, определяется реализацией. Поэтому компиляторы C++ будут применять имя для этих двух функций для их дифференциации. Возможно, мы назовем их foo_int и foo_float.

Поскольку C++ может это сделать, у нас нет проблем. Но extern "C" требует, чтобы компилятор применял правила именования C.

  • 0
    Я не знаю, если это умная или глупая вещь, исходящая от того, кто разработал эту функцию на языке ... Мне в основном приходится вручную кодировать все варианты T?
  • 0
    Если вы хотите, чтобы функции могли вызываться кодом C, то да. Вызывающая программа, скомпилированная с помощью компилятора C, не знает, как вызвать искаженную функцию имени.
Показать ещё 19 комментариев
3

"связь" - это немного вводящий в заблуждение термин. Главное, что extern "C" меняют название. То есть он создает имена символов в объектных файлах, которые совместимы с типом символов, которые создавал бы эквивалентный код C. Таким образом, он может связываться с объектным кодом C.... но это нечто иное, чем указание static или extern связи.

Но шаблоны не имеют эквивалента C, а имя mangling используется, чтобы удостовериться, что разные экземпляры данной шаблонной функции приводят к разным именам символов (так, чтобы компоновщик знал, какой из них использовать в данном месте).

Таким образом, нет способа предоставить шаблоны C linkage; вы просите компилятор сделать две принципиально несовместимые вещи.

  • 0
    Я согласен, что связывание действительно вводит в заблуждение, оно также звучит как повторение, когда вы используете extern который уже полностью связан со связыванием, и на самом деле он не помогает вам найти конкретную ошибку в определенной строке или семантике.
  • 0
    Ну, это все еще связь. Это своего рода внешняя связь. Конечно, нет никаких оснований объявлять что-то как искажающее С-стиль, если вы не намерены давать ему внешнюю связь.
Показать ещё 2 комментария
0

Ну, другие ответы объяснили, почему он не работает со стороны C++.

С стороны C есть рабочие раунды, но они не переносимы.

Вы можете просто не использовать ключевое слово extern "C", создавать функции, зависящие от имени, а затем в ссылке на C-код к фактическим искаженным именам.

Чтобы это было проще, вы могли бы также использовать функцию GCC abi::__cxa_demangle() сочетании со abi::__cxa_demangle() таблицей, чтобы вам не нужно было знать, что такое имена искалеченных функций (только их демаршированная подпись).

Но все это на самом деле.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню