可变参数模板的单独定义
Separate definitions of variadic templates
(最后一题在底部)
最近,我问 如何修复链接器错误(关于涉及模板 void 的多个定义的重复符号。
因为我在多个源文件中使用函数,所以建议我使用关键字 inline
允许在 header 中声明或将声明放在已编译的源文件中。
在我意识到 inline
有一些不好的影响后,我将我的声明放在源文件中。
现在没问题了,可变参数模板除外:
template<typename T, typename... Args>
void cleanup(T *t, Args&&... args);
我找到了一些明显的解决方案 - 但不是可变参数模板 - 使用 .tpp 文件(但它再次开始声明重复符号)或保留源文件并添加显式实例化。
但是void cleanup
有可能使用数百种参数组合,所以我不想显式实例化所有内容。
问题:
那么,我将如何处理
- 在源文件中保留可变参数模板定义,或者
- 将定义放入 .tpp 文件中而不获取重复符号,并最终避免使用
inline
?
.tpp 声明的 duplicate/undefined 符号错误示例和将上述模板定义分别放入源文件中。
duplicate symbol __Z7cleanupI10SDL_WindowJEEvPT_DpOT0_ in:
CMakeFiles/Game.dir/Game/main.cc.o
CMakeFiles/Game.dir/Game/RichTools/rtexture.cc.o
_
Undefined symbols for architecture x86_64:
"void cleanup<SDL_Renderer, SDL_Window*&>(SDL_Renderer*, SDL_Window*&&&)",
referenced from:
cleanQuit() in main.cpp.o
ld: symbol(s) not found for architecture x86_64
回答您的第一个问题的建议:内联或移动到源文件仅与您完全专用的函数有关 - 这些函数的参数列表为空 template <>
。
所以,这样做:
你的头文件:
// This shall be in header - it is not full specialization:
template<typename T, typename... Args>
void cleanup(T *t, Args&&... args){
//Cleanup the first item in the list
cleanup(t);
//Recurse to clean up the remaining arguments
cleanup(std::forward<Args>(args)...);
}
// These shall be only declared here, and implemented in source file,
// treat fully specialized function templates as regular functions
template<>
void cleanup<SDL_Window>(SDL_Window *win);
template<>
void cleanup<SDL_Renderer>(SDL_Renderer *ren);
template<>
void cleanup<SDL_Texture>(SDL_Texture *tex);
您的源文件:
template<>
void cleanup<SDL_Window>(SDL_Window *win){
if (!win){
return;
}
SDL_DestroyWindow(win);
}
template<>
void cleanup<SDL_Renderer>(SDL_Renderer *ren){
if (!ren){
return;
}
SDL_DestroyRenderer(ren);
}
template<>
void cleanup<SDL_Texture>(SDL_Texture *tex){
if (!tex){
return;
}
SDL_DestroyTexture(tex);
}
template<>
void cleanup<SDL_Surface>(SDL_Surface *surf){
if (!surf){
return;
}
SDL_FreeSurface(surf);
}
(最后一题在底部)
最近,我问
因为我在多个源文件中使用函数,所以建议我使用关键字 inline
允许在 header 中声明或将声明放在已编译的源文件中。
在我意识到 inline
有一些不好的影响后,我将我的声明放在源文件中。
现在没问题了,可变参数模板除外:
template<typename T, typename... Args>
void cleanup(T *t, Args&&... args);
我找到了一些明显的解决方案 - 但不是可变参数模板 - 使用 .tpp 文件(但它再次开始声明重复符号)或保留源文件并添加显式实例化。
但是void cleanup
有可能使用数百种参数组合,所以我不想显式实例化所有内容。
问题: 那么,我将如何处理
- 在源文件中保留可变参数模板定义,或者
- 将定义放入 .tpp 文件中而不获取重复符号,并最终避免使用
inline
?
.tpp 声明的 duplicate/undefined 符号错误示例和将上述模板定义分别放入源文件中。
duplicate symbol __Z7cleanupI10SDL_WindowJEEvPT_DpOT0_ in:
CMakeFiles/Game.dir/Game/main.cc.o
CMakeFiles/Game.dir/Game/RichTools/rtexture.cc.o
_
Undefined symbols for architecture x86_64:
"void cleanup<SDL_Renderer, SDL_Window*&>(SDL_Renderer*, SDL_Window*&&&)",
referenced from:
cleanQuit() in main.cpp.o
ld: symbol(s) not found for architecture x86_64
回答您的第一个问题的建议:内联或移动到源文件仅与您完全专用的函数有关 - 这些函数的参数列表为空 template <>
。
所以,这样做:
你的头文件:
// This shall be in header - it is not full specialization:
template<typename T, typename... Args>
void cleanup(T *t, Args&&... args){
//Cleanup the first item in the list
cleanup(t);
//Recurse to clean up the remaining arguments
cleanup(std::forward<Args>(args)...);
}
// These shall be only declared here, and implemented in source file,
// treat fully specialized function templates as regular functions
template<>
void cleanup<SDL_Window>(SDL_Window *win);
template<>
void cleanup<SDL_Renderer>(SDL_Renderer *ren);
template<>
void cleanup<SDL_Texture>(SDL_Texture *tex);
您的源文件:
template<>
void cleanup<SDL_Window>(SDL_Window *win){
if (!win){
return;
}
SDL_DestroyWindow(win);
}
template<>
void cleanup<SDL_Renderer>(SDL_Renderer *ren){
if (!ren){
return;
}
SDL_DestroyRenderer(ren);
}
template<>
void cleanup<SDL_Texture>(SDL_Texture *tex){
if (!tex){
return;
}
SDL_DestroyTexture(tex);
}
template<>
void cleanup<SDL_Surface>(SDL_Surface *surf){
if (!surf){
return;
}
SDL_FreeSurface(surf);
}