可变参数模板的单独定义

Separate definitions of variadic templates

(最后一题在底部)

最近,我问 如何修复链接器错误(关于涉及模板 void 的多个定义的重复符号。

因为我在多个源文件中使用函数,所以建议我使用关键字 inline 允许在 header 中声明或将声明放在已编译的源文件中。

在我意识到 inline 有一些不好的影响后,我将我的声明放在源文件中。

现在没问题了,可变参数模板除外:

template<typename T, typename... Args>
void cleanup(T *t, Args&&... args);

我找到了一些明显的解决方案 - 但不是可变参数模板 - 使用 .tpp 文件(但它再次开始声明重复符号)或保留源文件并添加显式实例化。

但是void cleanup有可能使用数百种参数组合,所以我不想显式实例化所有内容。

问题: 那么,我将如何处理

  1. 在源文件中保留可变参数模板定义,或者
  2. 将定义放入 .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);
}