Невозможно скомпилировать какой-либо код шаблона с помощью cl.exe

Я пытаюсь скомпилировать некоторый код 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?

Спасибо за прочтение моего поста, любые рекомендации приветствуются.

extern "C" __declspec(dllexport) T __stdcall TestFx(T arg) {return arg;} Экспортировать шаблон нельзя. Вы можете создать экземпляр шаблона и экспортировать его.
drescherjm 08.04.2024 02:25

@drescherjm спасибо за ваш комментарий; Вы имеете в виду, что мне нужно будет создать явные версии моего шаблона для каждого типа данных, который я планирую использовать, и вручную экспортировать каждый из них?

Runsva 08.04.2024 08:29

По сути, это «Альтернативное решение» для этого ответа: https://stackoverflow.com/a/495056/487892

drescherjm 08.04.2024 14:59
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
101
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, вы проигнорировали первую ошибку и опубликовали вторую. Если бы вы начали исправлять свой код с самого начала 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.

Runsva 08.04.2024 02:04

Мой код только исправляет ошибку. Вы должны добавить main(), как во втором коде.

3CxEZiVlQ 08.04.2024 02:09

Хорошо, я еще немного повозился с кодом и сделал несколько открытий. Помимо того, что вы упомянули, еще одна основная проблема заключалась в том, что мне не хватало флагов /LD, /EHsc и /link в моей команде компиляции cl.exe, то есть она пыталась скомпилировать код в EXE, а не в DLL, как я хотел, поэтому я получал ошибку LNK1561, поскольку не мог найти main(). Выполнение cl.exe /LD /EHsc /std:c++20 test.cpp /link /out:test.dll и наряду с упомянутым вами изменением по удалению ключевого слова extern теперь экспортирует DLL. Однако...

Runsva 08.04.2024 08:24

Однако экспортированный test.dll, похоже, не содержит функции TestFx. Выполнение dumpbin /exports test.dll не показывает функцию TestFx должным образом. Есть идеи, почему это может происходить?

Runsva 08.04.2024 08:25
TestFx — шаблон, шаблоны не экспортируются. Они либо должны быть созданы для определенных типов в вашей DLL, либо шаблон должен находиться в заголовочном файле.
3CxEZiVlQ 08.04.2024 08:54

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

Runsva 08.04.2024 09:16

В противном случае просто оставьте шаблон в заголовке без __declspec(dllexport) и __stdcall и используйте его так же, как и без dll.

drescherjm 08.04.2024 15:20

Другие вопросы по теме