Почему функция C / C ++ с предварительно обработанными параметрами может правильно связываться, только если она определена в файле заголовка? - PullRequest
0 голосов
/ 07 мая 2020

Я работаю с CLion (используя CMake) в проекте, который включает внешнюю библиотеку, которая переопределяет типы в зависимости от определения макроса. Например, если определен макрос флага, то тип структуры MyType2D заменяется на MyType3D. У меня также есть два файла, A.h и A.cpp, где файл заголовка содержит класс омонима с двумя объявлениями функций: f1 и f2. Разница между f1 и f2 состоит в том, что f1 имеет параметры, типы которых не изменяются препроцессором, а f2 имеет параметры, типы которых - MyType3D или MyType2D, в зависимости от того, является ли макрос флага определен или нет.

Теперь при сборке проекта, в случае, если макрос флага не определен, все компилируется, связывается и выполняется правильно. Проблема возникает, когда макрос флага определен, а затем типы параметров в f2 переключаются на MyType3D. В этом случае, когда я создаю проект, компиляция завершается успешно, но связывание не удается с сообщением об ошибке:

Undefined symbols for architecture x86_64:
  "A::f2(MyType3D const*)", referenced from:
      _main in main_3d.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Обратите внимание, что во время компиляции создается объектный файл A.o, поскольку я включил его вместе с main_3d.cpp в списке источников в CMake. Я также проверил это, потому что другая функция, f1, не выдает никаких ошибок связи, и я вызываю ее перед вызовом f2.

Однако вот чего я не могу понять: если я перемещаю определение из f1 из A.cpp в A.h, имея определенную макрос флага, код компилируется и работает как положено. В своей попытке исправить / понять это, я сделал следующее:

// ...
#ifdef FlagMacro
    void f1( MyType3D const* var );
#else
    void f1( MyType2D const* var );
#endif
// ...

как в A.h, так и A.cpp (с соответствующим определением функции в исходном файле), но ошибка сохраняется во время связывания с тем же сообщением.

Мой вопрос: почему я должен определять функцию в заголовочном файле (как часть класса A), когда препроцессор используется для изменения типов параметров функции?

1 Ответ

0 голосов
/ 08 мая 2020

Как оказалось, FlagMacro не был определен во время компиляции A.cpp в A.o. Несмотря на то, что FlagMacro был установлен во внешнем файле заголовка (например, p4est_to_p8est.h), включенном в мой main_3d.cpp, который также включал A.h, A.cpp не смог увидеть FlagMacro, потому что у меня не было явный #include p4est_to_p8est.h в A.h.

...