C++: candidate template ignored: invalid explicitly-specified argument for template parameter
Asked Answered
N

1

11

I have this function header:

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)

This is how I use it:

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

This is GetPixel and PutPixel:

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) { /* .. */ }

And I get this error:

note: candidate template ignored: invalid explicitly-specified argument for template parameter 'getFunc' [3]

Why?

Niggling answered 25/12, 2011 at 13:39 Comment(2)
I think functions with internal linkage (static) cannot be used as non-type template arguments.Decrepitate
@Xeo: You are correct. Your namespace suggestion is a good one.Rosarosabel
M
9

I suspect that all those functions are free functions. When you declare a free function static, it gains internal linkage. Non-type template parameters, in C++03, must have external linkage. Just remove static in front of the functions.

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> >();
}

This modified example compiles fine on Clang 3.1 and GCc 4.4.5 in C++98 and C++11 mode, no warnings. If I leave the static in, I get a similar error + note to what you got with Clang, and GCC spits out the vital information (scroll to the right, "has not external linkage"):

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

A template-argument for a non-type, non-template template-parameter shall be one of:

  • [...]

  • the address of an object or function with external linkage [...]

  • [...]

Note that C++11 changed the wording and allows functions with internal linkage too now:

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

A template-argument for a non-type, non-template template-parameter shall be one of:

  • [...]

  • a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage [...]

  • [...]

Clang does currently not obey to this in C++11 mode, it still only allows functions with external linkage.

Multitudinous answered 25/12, 2011 at 14:7 Comment(8)
This answer is only true for c++03. Current c++ allows also internal linkage.Comptroller
Ah. I wonder why that is. The whole purpose of this construct is that the compiler has a chance to inline the function.Niggling
@Niggling External and internal linkage got nothing to do with wether the compiler will inline stuff. The sole fact that you're using function pointers will make it very unlikely to happen. Best you can do is just use a functor and pass that. With that, the compiler has all the info it needs to inline the call.Multitudinous
@Xeo: You misunderstood me. I use this construct solely to be able to construct a special version of OperateOnSurface with a given known static inlined function. From the view of the compiler, this shouldn't really be different than a functor. And it makes the code cleaner.Niggling
@Albert: No, this code is not cleaner than the equivalent functor version. Also, it's way more likely that the compiler will inline the functor version.Multitudinous
@Xeo: I think it is. Maybe a matter of taste. However, you often have functions anyway which you want to use there. See this comparison.Niggling
@Albert: Did you compile that without optimizations? Seems so atleast. Also note that the inline keyword is a farce for making functions inlined. The compiler is free to ignore it and does so most of the time. Same goes for not using it, the compiler is still free to inline such functions. It's only useful if you want to define a non-template function in a header, as you would get "multiple definition"-errors without it. That's about the only use left.Multitudinous
@Xeo: Without any option, i.e. I think it is equal to -O0 for G++. And just try it yourself, you'll see that in this case, it really inlines exactly when there is inline. And yea, I know that the compiler doesn't strictly have to follow that. Anyway, it was a comparison function pointers vs functors and which solution seems more clean and shorter.Niggling

© 2022 - 2024 — McMap. All rights reserved.