4

When I try compiling

template<bool val>
struct boolean { static const bool value = val; };

template<typename T>
struct is_callable : boolean<sizeof((*(T*)0)()) >= 0> { };            // error!

int main(void) { bool b = is_callable<int (*)()>::value; }

I get:

error C2064: term does not evaluate to a function taking 0 arguments  
    see reference to class template instantiation 'is_callable<T>' being compiled

I'm pretty sure int (*)() is callable with 0 arguments... so why doesn't this compile?

user541686
  • 205,094
  • 128
  • 528
  • 886
  • @KerrekSB: Huh, that's quite interesting... I tried it with VC 2010 and it also gave an error. Is it a bug then? I can't tell, since there's a null pointer getting dereferenced, but practically speaking I don't see anything wrong with it... – user541686 Jan 06 '12 at 02:22
  • 5
    There's no dereference. `sizeof` does not evaluate its argument. – Kerrek SB Jan 06 '12 at 02:24

3 Answers3

0

You could just use simple template specialization.

#include <stdio.h>

template<typename T>
struct func_with_zero_args { static const bool value = false; };
template<>
struct func_with_zero_args <int (*)()> { static const bool value = true; };

#define STRINGIFY(t) "" #t
#define TEST(t) printf(STRINGIFY(t) ": %s\n", (func_with_zero_args<t>::value ? "yes" : "no"));

int
main(int argc, const char* argv[])
{
    TEST(void);
    TEST(void (*)(void));
    TEST(void (*)(int));
    TEST(int (*)(void));
    TEST(int (*)(int));
    return 0;
}

Generates (using g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3)

void: no
void (*)(void): no
void (*)(int): no
int (*)(void): yes
int (*)(int): no
kfsone
  • 23,617
  • 2
  • 42
  • 74
0

The problem is not the use of int(). You can completely remove that from the example and get the same error. The problem is the sizeof expression itself when used as a non-type template argument. Example

template<bool val>
struct boolean { };

template<typename T>
struct is_callable : boolean<sizeof((*(T*)0)()) >= 0>  // Error
{ 
  void Test() 
  {
    auto x = sizeof((*(T*)0)()) >= 0;  // Compiles
  }

}; 

Hopefully another C++ guy can come along and determine if this sizeof expression is simply illegal as a type argument or if this is just a limitation in the MS C++ compiler.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
0

For me this works.

    typedef int (*X)();

    template<typename T>
    struct is_callable : boolean<sizeof((*(X*)(T*)0)()) >= 0> { };            // works!

So, it looks like the compiler is not sure that you will always pass a function pointer to T when you instantiate the template class !. So, force the compiler with an explicit cast.

[Edit] : Also, on further thinking, I don't understand what you are really trying to do. Are you trying to measure the size of a function pointer which takes a single parameter? How this is going to be different for functions with different return types? Why do you need template at all for a constant expression (which is sizeof(void*))?

Please check this thread for more understanding What is guaranteed about the size of a function pointer?

Community
  • 1
  • 1
PermanentGuest
  • 5,213
  • 2
  • 27
  • 36