c – 在编写库时是否应将可见性/导出宏应用于模板?

前端之家收集整理的这篇文章主要介绍了c – 在编写库时是否应将可见性/导出宏应用于模板?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
构建C DLL或共享库时__attribute __((__ visibility __(“default”)))或__declspec(dllexport)经常通过宏附加到那些应该可供消费者使用的具体符号(类,函数等).库,其他符号默认为具有内部可见性.

但是应该如何处理内联函数或模板?

似乎对于内联函数,答案应该是不需要注释.如果定义内联函数标题的使用者实际内联函数,则不需要符号.如果消费者改为发出外线定义,那仍然可以.唯一的缺点是DLL内部和每个消费库内部的内联函数的定义可能不同.所以,如果你期望可靠地比较内联函数的地址,你可能会遇到麻烦,但无论如何这似乎都很粗略.

鉴于该论点,似乎由于模板主体通常对于消费TU完全可见,因此应用相同的逻辑.

我觉得这里可能存在一些关于’extern模板’和显式实例化的细微之处.

有没有人对可见性属性如何遵循内联函数和模板有具体的指导?

解决方法

内联函数不是外部可见的(没有链接,IIRC),因此它们不能从DLL导出.如果它们是公开的,那么它们将完全写入库的头文件中,并且每个用户都会重新编译它.

正如您在问题中所说,由于内联代码在每个使用该库的模块中都会重新编译,因此对于库的未来版本,可能会出现问题.

我对共享库中的内联函数的建议是它们应该仅用于非常简单的任务或绝对通用的函数.请注意,将公共内联函数转换为非内联函数是ABI中断更改.

例如:

>类似memcpy的功能.排队!
>类似bswap的功能.排队!
>类构造函数.不要内联!即使它现在什么都不做,您可能希望在未来版本的库中执行某些操作.在库中编写非内联空构造函数并将其导出.
>一个类析构函数.不要内联!与上面相同.

在实践中,内联函数可以具有多个不同的地址这一事实并不重要.

关于extern模板和显式实例化,只需要小心,它们就可以用来从库中导出模板.如果模板实例仅限于特定的一组案例,您甚至可以避免将模板代码复制到头文件中.

注1:在下面的例子中,我将使用一个简单的函数模板,但类模板将完全相同.
注2:我正在使用GCC语法. MSC代码是类似的,我想你已经知道差异了(我没有MSC编译器来测试).

例1

public_foo.h

template<int N> int foo(int x); //no-instantiable template

shared_foo.cpp

#include "public_foo.h"

//Instantiate and export

template __attribute__ ((visibility("default")))
int foo<1>(int x);

template __attribute__ ((visibility("default")))
int foo<2>(int x);

program.cpp

#include "public_foo.h"

int main()
{
    foo<1>(42); //ok!
    foo<2>(42); //ok!
    foo<3>(42); //Linker error! this is not exported and not instantiable
}

相反,您的模板应该是可以自由实例化的,但是您希望它以特定的方式经常使用,您可以从库中导出这些模板.想想std :: basic_string:它最有可能被用作std :: basic_string< char>和std :: basic_string< wchar_t>,但不太可能是std :: basic_string< float>.

例2

public_foo.h

template<int N> int foo(int x)
{
    return N*x;
}

//Do not instantiate these ones: they are exported from the library
extern template int foo<1>(int x);
extern template int foo<2>(int x);

shared_foo.cpp

#include "public_foo.h"

//Instantiate and export

template __attribute__ ((visibility("default")))
int foo<1>(int x);

template __attribute__ ((visibility("default")))
int foo<2>(int x);

program.cpp

#include "public_foo.h"

int main()
{
    foo<1>(42); //ok,from library
    foo<2>(42); //ok,from library
    foo<3>(42); //ok,just instantiated
}

猜你在找的C&C++相关文章