显式模板示例化的C++符号可见性

3phpmpom  于 2023-08-09  发布在  其他
关注(0)|答案(1)|浏览(149)

我创建了一个共享库,并使用默认的符号可见性“隐藏”,即,我必须明确修改任何应导出的可见性。此外,我在头文件中定义了模板,并在库的源文件中显式地示例化它们,以强制编译(并对库用户隐藏实现)。对于此头文件foo.hpp

#include <gmpxx.h>
  
template <typename Number>
__attribute__((visibility("default")))
Number add(const Number& a, const Number& b);

字符串
这个源文件foo.cpp

#include "foo.hpp"

template <typename Number>
Number add(const Number& a, const Number& b)
{
  return a + b;
}

template double add(const double& a, const double& b);
template int add(const int& a, const int& b);
template mpq_class add(const mpq_class& a, const mpq_class& b);


编译与

g++ -fPIC -fvisibility=hidden -c foo.cpp
g++ -fPIC -shared -o libfoo.so foo.o


给出以下(相关)符号(通过nm -CD libfoo.so获得):

__gmpq_add
__gmpq_init
double add<double>(double const&, double const&)
int add<int>(int const&, int const&)


但是,我也希望mpq_class实现有一个符号。当然,如果我现在链接到这个库并尝试调用add<mpq_class>,那么我会得到一个未定义的符号错误。我可以通过在foo.cpp中为mpq_class添加一个显式的示例化来强制导出,该示例化被显式地标记为导出:

template <>
__attribute__((visibility("default")))
mpq_class add(const mpq_class& a, const mpq_class& b)
{
  return a + b;
}


当然,这没有多大意义,因为我重复了代码,或者我必须为每个这样的函数提供一个联合实现。对于模板类,这似乎只会发生在构造函数和析构函数上,而不会发生在成员上。
我想知道为什么会这样。我猜这是因为mpq_class本身就是一个模板类,但我觉得很奇怪。

eagi6jfj

eagi6jfj1#

这个线程可能是一个僵尸,但我正在研究这个问题,并认为这些信息可能会帮助别人!
我从这段代码开始:
在头文件中:

#ifdef MY_LIB_STATIC
#    define MY_LIB_API
#elif defined(WIN32)
#    ifdef MY_LIB_EXPORTS
#        define MY_LIB_API __declspec(dllexport)
#    else
#        define MY_LIB_API __declspec(dllimport)
#    endif
#else
#     ifdef MY_LIB_EXPORTS
#         define MY_LIB_API __attribute__((visibility("default")))
#     else
#         define MY_LIB_API
#     endif
#endif

template <class T>
class Container
{
public:

    size_type size() const;
};

字符串
在C++文件中:

template <class T>
size_t Container<T>::size() const
{
    return m_impl->size();
}

template class MY_LIB_API Container<Port*>;  // Port is a class


然后我从客户端MySourceFile.cpp使用调用size()。
这在Windows/Visual Studio上工作正常,但在Linux/gcc上使用-fvisibility=hidden时,它会给出如下错误:

ld: MySourceFile.cpp:115: undefined reference to `Container<Port*>::size() const'


解决方案是将MY_LIB_API放在每个声明中,因此在头文件中:

template <class T>
class MY_LIB_API Container
{
public:

    size_type size() const;
};


我猜是

  • 默认可见性是隐藏的。
  • 如果类上没有可见性属性,则使用自动设置hidden。
  • 现在,有两个相互竞争的类声明,其中一个声明为“default”的声明失败了,所以它被隐藏了。

不幸的是,使用单词“default”表示非隐藏,而不是表示使用命令行上指定的默认值,这使得这一切有点迟钝。

相关问题