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?

Albert
  • 65,406
  • 61
  • 242
  • 386
  • Names starting with underscore and capital letter are reserved, don't use them. Also, you're missing vital information: *How do you call that function?* What parameters? – Xeo Dec 25 '11 at 13:42
  • Just so you know, names that contain double underscore anywhere are just as reserved as names starting with underscore and capital letter. – Xeo Dec 25 '11 at 13:54
  • @Xeo: Thanks for the remark. What about three? What is a good convention for these kind of abstract functions? (In all such cases, I have also versions of these functions without the underscores.) – Albert Dec 25 '11 at 13:59
  • Three underscores contain two underscores, so a no-go. Just put them in a `namespace detail`. Also, are those free functions or static member functions? Also, which compiler are you using? – Xeo Dec 25 '11 at 14:01
  • @Albert: You might try *ending* your variable names with one or more underscores. For example, the Google style guide uses a single underscore at the end of variable names for class member variables. – Ben Hocking Dec 25 '11 at 14:03
  • @Ben: Double underscores *anywhere* in a name are reserved. – Xeo Dec 25 '11 at 14:04
  • I think functions with internal linkage (`static`) cannot be used as non-type template arguments. – Kerrek SB Dec 25 '11 at 14:05
  • @Xeo: You are correct. Your namespace suggestion is a good one. – Ben Hocking Dec 25 '11 at 14:09

1 Answers1

8

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.

Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • This answer is only true for c++03. Current c++ allows also internal linkage. – Johannes Schaub - litb Dec 25 '11 at 14:17
  • Ah. I wonder why that is. The whole purpose of this construct is that the compiler has a chance to inline the function. – Albert Dec 25 '11 at 14:36
  • @Albert 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. – Xeo Dec 25 '11 at 15:41
  • @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. – Albert Dec 25 '11 at 16:01
  • @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. – Xeo Dec 25 '11 at 16:03
  • @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](https://gist.github.com/1519596). – Albert Dec 25 '11 at 18:44
  • @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. – Xeo Dec 25 '11 at 20:54
  • @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. – Albert Dec 25 '11 at 22:02