C++:候选模板被忽略:模板参数的显式指定无效。

11

我有这个函数头:

template <
    bool src_alpha,
    int sbpp, int dbpp,
    typename T1, typename T2,
    Color (*getFunc)(T1 data, Uint8* addr),
    void (*putFunc)(T2 data, Uint8* addr, Color c)
>
static void OperateOnSurfaces(T1 data1, T2 data2, SDL_Surface * bmpDest, SDL_Surface * bmpSrc, SDL_Rect& rDest, SDL_Rect& rSrc)

我是这样使用它的:

OperateOnSurfaces<
    true,
    32, 32,
    SDL_PixelFormat*, SDL_PixelFormat*,
    GetPixel<true,32>, PutPixel<true,true,32> >(
    bmpSrc->format, bmpDest->format,
    bmpDest, bmpSrc, rDest, rSrc);

这是GetPixelPutPixel

template<bool alpha, int bpp>
static Color GetPixel(SDL_PixelFormat* format, Uint8* addr) { /* .. */ }

template<bool alpha, bool alphablend, int bpp>
static void PutPixel(SDL_PixelFormat* format, Uint8* addr, Color col) { /* .. */ }

我遇到了这个错误:

注意:候选模板被忽略:模板参数 'getFunc' 的显式指定的参数无效[3]

为什么会出现这种情况?


以下划线和大写字母开头的名称是保留的,请勿使用。此外,您缺少重要信息:如何调用该函数? 有哪些参数? - Xeo
只是提醒一下,任何地方包含双下划线的名称和以下划线和大写字母开头的名称一样被保留。 - Xeo
三个下划线包含两个下划线,所以不行。只需将它们放在 namespace detail 中即可。此外,这些是自由函数还是静态成员函数?另外,您使用的是哪个编译器? - Xeo
我认为具有内部链接(static)的函数无法用作非类型模板参数。 - Kerrek SB
@Xeo:你是正确的。你的命名空间建议很好。 - Ben Hocking
显示剩余3条评论
1个回答

8
我怀疑所有这些函数都是自由函数。当你声明一个自由函数为static时,它会获得内部链接。在C++03中,非类型模板参数必须具有外部链接 。只需在函数前面移除static即可。
template <
    bool src_alpha,
    int sbpp, int dbpp,
    typename T1, typename T2,
    char (*getFunc)(T1 data, unsigned* addr),
    void (*putFunc)(T2 data, unsigned* addr, char c)
>
void OperateOnSurfaces(){}

template<bool alpha, int bpp>
char GetPixel(void* format, unsigned* addr);

template<bool alpha, bool alphablend, int bpp>
void PutPixel(void* format, unsigned* addr, char col);

int main(){
    OperateOnSurfaces<
        true,
        32, 32,
        void*, void*,
        GetPixel<true,32>, PutPixel<true,true,32> >();
}

这个修改后的示例在C++98和C++11模式下可以在Clang 3.1和GCc 4.4.5上编译通过,没有警告。如果我保留static,那么我会得到与您在Clang中得到的类似错误+注释,并且GCC输出关键信息(向右滚动,“没有外部链接”):

15:02:38 $ g++ t.cpp
t.cpp: In function ‘int main()’:
t.cpp:21: error: ‘GetPixel<true, 32>’ is not a valid template argument for type ‘char (*)(void*, unsigned int*)’ because function ‘char GetPixel(void*, unsigned int*) [with bool alpha = true, int bpp = 32]’ has not external linkage
t.cpp:21: error: ‘PutPixel<true, true, 32>’ is not a valid template argument for type ‘void (*)(void*, unsigned int*, char)’ because function ‘void PutPixel(void*, unsigned int*, char) [with bool alpha = true, bool alphablend = true, int bpp = 32]’ has not external linkage
t.cpp:21: error: no matching function for call to ‘OperateOnSurfaces()’

(C++03) §14.3.2 [temp.arg.nontype] p1

非类型、非模板的模板参数模板实参应该是以下之一:

  • [...]

  • 具有外部链接的对象或函数的地址 [...]

  • [...]

请注意,C++11更改了措辞,现在允许具有内部链接的函数:

(C++11) §14.3.2 [temp.arg.nontype] p1

非类型、非模板的模板参数模板实参应该是以下之一:

  • [...]

  • 一个常量表达式(5.19),它指定具有静态存储期间和外部或内部链接的对象的地址或具有外部或内部链接的函数 [...]

  • [...]

Clang目前在C++11模式下没有遵守此规定,仍然仅允许具有外部链接的函数。


这个答案仅适用于c++03。当前的c++也允许内部链接。 - Johannes Schaub - litb
@Albert 外部和内部链接与编译器是否会内联代码无关。你使用函数指针的事实将使这种情况变得不太可能发生。你能做的最好的事情就是使用一个函数对象并传递它。这样,编译器就拥有了所有需要内联调用的信息。 - Xeo
@Xeo: 你误解了我的意思。我仅使用这个结构来构建一个特殊版本的 OperateOnSurface,其中包含一个已知的静态内联函数。从编译器的角度来看,这与一个函数对象并没有真正的区别。而且它使代码更清晰。 - Albert
@Albert:不,这段代码并不比等效的函数对象版本更清晰。而且,编译器更有可能将函数对象版本内联。 - Xeo
@Xeo:我认为是这样的。也许只是个人口味问题。然而,你通常会有想要在那里使用的函数。请参见此比较 - Albert
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接