如何从共享库中导出模板实例化

问题描述 投票:0回答:1

我有这个标题:


#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模板实例化的正确且可移植的方法是什么(可能包括模板各部分的模板专业化?)是什么?

c++ shared-libraries template-specialization extern explicit-instantiation
1个回答
0
投票
您只需要在此行前面输入MYLIB_EXPORT

int Templ<int>::getNum() const

© www.soinside.com 2019 - 2024. All rights reserved.