Я пытаюсь скомпилировать некоторый код C++ в файл DLL, используя cl.exe
в Windows 10. Похоже, что я вообще не могу скомпилировать какой-либо код с использованием шаблонов из-за ошибки C2187
с помощью командной строки разработчика Visual Studio 2022.
В качестве простого примера попытаемся скомпилировать следующий test.cpp
файл всего с одной функцией TestFx
, которая напрямую возвращает полученный шаблонный аргумент:
template <typename T>
extern "C" __declspec(dllexport) T __stdcall TestFx(T arg) {return arg;}
Команда cl.exe /std:c++20 test.cpp
приводит к:
C2187: syntax error: 'string' was unexpected here
Я не совсем уверен, что эта ошибка пытается мне сказать. Судя по всему, документация по ошибке C2187
в Visual Studio отсутствует, и у нее нет страницы в официальном списке ошибок компилятора Microsoft.
Сначала я подумал, что эта ошибка может быть вызвана тем, что string
не определен, когда компилятор создает все версии шаблона TestFx
, но добавление include <iostream>
или include <string>
и using namespace std;
приводит к той же ошибке.
Меня это еще больше сбивает с толку, потому что попытка скомпилировать что-то вроде:
#include <iostream>
template <typename T>
T TestFx(T arg)
{
return arg;
}
int main()
{
std::cout << TestFx(1) << "\n";
std::cout << TestFx(5.5) << "\n";
std::cout << TestFx("test") << "\n";
return 0;
}
Без проблем работает в обычной Visual Studio при компиляции в EXE:
1
5.5
test
Мне не хватает некоторых флагов компилятора или компоновщика, чтобы можно было скомпилировать шаблоны в DLL с помощью cl.exe
?
Спасибо за прочтение моего поста, любые рекомендации приветствуются.
@drescherjm спасибо за ваш комментарий; Вы имеете в виду, что мне нужно будет создать явные версии моего шаблона для каждого типа данных, который я планирую использовать, и вручную экспортировать каждый из них?
По сути, это «Альтернативное решение» для этого ответа: https://stackoverflow.com/a/495056/487892
Похоже, вы проигнорировали первую ошибку и опубликовали вторую. Если бы вы начали исправлять свой код с самого начала error C2988: unrecognizable template declaration/definition
, вы бы обнаружили, что шаблоны нельзя объявлять с помощью extern "C"
. Это скомпилировано хорошо
template <typename T>
__declspec(dllexport) T __stdcall TestFx(T arg) {
return arg;
}
Кстати, я не вижу никаких преимуществ в использовании __declspec(dllexport)
и __stdcall
с шаблоном, реализованным в заголовочном файле.
Я не проигнорировал никаких ошибок, я просто загрузил изображение того, что показала мне командная строка, когда я попытался скомпилировать код. Кроме того, когда я пытаюсь скомпилировать показанный вами код, я получаю ошибку LNK1561: entry point must be defined
. Я также не делаю это в заголовочном файле, это файл cpp
под названием test.cpp
.
Мой код только исправляет ошибку. Вы должны добавить main()
, как во втором коде.
Хорошо, я еще немного повозился с кодом и сделал несколько открытий. Помимо того, что вы упомянули, еще одна основная проблема заключалась в том, что мне не хватало флагов /LD
, /EHsc
и /link
в моей команде компиляции cl.exe
, то есть она пыталась скомпилировать код в EXE, а не в DLL, как я хотел, поэтому я получал ошибку LNK1561
, поскольку не мог найти main()
. Выполнение cl.exe /LD /EHsc /std:c++20 test.cpp /link /out:test.dll
и наряду с упомянутым вами изменением по удалению ключевого слова extern
теперь экспортирует DLL. Однако...
Однако экспортированный test.dll
, похоже, не содержит функции TestFx
. Выполнение dumpbin /exports test.dll
не показывает функцию TestFx
должным образом. Есть идеи, почему это может происходить?
TestFx
— шаблон, шаблоны не экспортируются. Они либо должны быть созданы для определенных типов в вашей DLL, либо шаблон должен находиться в заголовочном файле.
ах, ладно, другими словами, шаблоны в этом случае будут генерировать версии функции только для типа данных, с которым я явно ее использую, а не для каждого возможного типа данных, который он может найти. Это имеет смысл, спасибо. Если вы измените свой ответ на сообщение, включив это в него, я приму это как ответ.
В противном случае просто оставьте шаблон в заголовке без __declspec(dllexport)
и __stdcall
и используйте его так же, как и без dll.
extern "C" __declspec(dllexport) T __stdcall TestFx(T arg) {return arg;}
Экспортировать шаблон нельзя. Вы можете создать экземпляр шаблона и экспортировать его.