我有这个标题:
#pragma once
#if _MSC_VER
# ifdef mylib_EXPORTS
# define MYLIB_EXPORT __declspec(dllexport)
# else
# define MYLIB_EXPORT __declspec(dllimport)
# endif
#else
# ifdef mylib_EXPORTS
# define MYLIB_EXPORT __attribute__((visibility("default")))
# else
# define MYLIB_EXPORT
# endif
#endif
template<typename T>
class Templ
{
public:
T getNum() const;
T getAnotherNum() const;
};
#ifndef mylib_EXPORTS
extern template class MYLIB_EXPORT Templ<int>;
#endif
使用此实现:
#include "mylib.h"
template<typename T>
T Templ<T>::getNum() const
{
return 7;
}
template<typename T>
T Templ<T>::getAnotherNum() const
{
return 5;
}
#if 0
template<>
int Templ<int>::getNum() const
{
return 42;
}
#endif
template class MYLIB_EXPORT Templ<int>;
和此消费者:
#include "mylib.h"
#include <iostream>
int main()
{
Templ<int> ti;
std::cout << ti.getNum() << " -- " << ti.getAnotherNum() << std::endl;
return 0;
}
和以下CMakeLists.txt:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(cpptest)
if (NOT WIN32)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined")
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
endif()
add_compile_options(-Werror)
add_library(mylib SHARED mylib.cpp)
add_executable(myexe main.cpp)
target_link_libraries(myexe PRIVATE mylib)
如果我使用MSVC或GCC进行构建和运行,则会获得预期的输出:
7 -- 5
但是,如果我在mylib.cpp中启用了模板专用化,那么我的GCC编译失败:
$ cmake --build .
[1/3] Building CXX object CMakeFiles/mylib.dir/mylib.cpp.o
FAILED: CMakeFiles/mylib.dir/mylib.cpp.o
/usr/lib/ccache/c++ -Dmylib_EXPORTS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden
-Werror -MD -MT CMakeFiles/mylib.dir/mylib.cpp.o -MF CMakeFiles/mylib.dir/mylib.cpp.o.d -o
CMakeFiles/mylib.dir/mylib.cpp.o -c ../mylib.cpp
../mylib.cpp:24:29: error: type attributes ignored after type is already defined [-Werror=attributes]
template class MYLIB_EXPORT Templ<int>;
^~~~~~~~~~
cc1plus: all warnings being treated as errors
ninja: build stopped: subcommand failed.
和MSVC:
LINK Pass 1: command "C:\PROGRA~2\MICROS~3.0\VC\bin\amd64\link.exe /nologo CMakeFiles\myexe.dir
\main.cpp.obj /out:myexe.exe /implib:myexe.lib /pdb:myexe.pdb /version:0.0 /machine:x64 /debug
/INCREMENTAL /subsystem:console mylib.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib
ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST
/MANIFESTFILE:CMakeFiles\myexe.dir/intermediate.manifest CMakeFiles\myexe.dir/manifest.res" failed
(exit code 1120) with the following output:
main.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: int __cdecl
Templ<int>::getNum(void)const " (__imp_?getNum@?$Templ@H@@QEBAHXZ) referenced in function main
myexe.exe : fatal error LNK1120: 1 unresolved externals
ninja: build stopped: subcommand failed.
并带有叮当声:
: && /usr/lib/ccache/clang++ CMakeFiles/myexe.dir/main.cpp.o -o myexe -Wl,-rpath,/home/stephen
/dev/src/playground/cpp/build libmylib.so && :
CMakeFiles/myexe.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x14): undefined reference to `Templ<int>::getNum() const'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
从共享库到dllexport模板实例化的正确且可移植的方法是什么(可能包括模板各部分的模板专业化?)是什么?
MYLIB_EXPORT
:int Templ<int>::getNum() const