3

What I'm trying to do is create a template function that stores a generic function pointer and information about how to cast to it's actual type. This is being used by my script binding API to make C++ function calls from Python for a game engine. In the process of porting this to OSX using XCode4 with LLVM, I have run into an error. This sample code compiles and runs fine in Visual Studio 2012, but gives me the error "No matching function for call to 'Call'" with LLVM.

#include <iostream>

void testfun (int i)
{
  std::cout << "Hello World " << i << std::endl;
}

typedef void BasicFunction ();

template <BasicFunction* fn, typename T0>
void Call (void(*f)(T0), T0 i)
{
  reinterpret_cast<decltype(f)>(fn)(i);
}

int main(int argc, const char * argv[])
{
  Call<reinterpret_cast<BasicFunction*>(testfun)>(testfun, 5);
  return 0;
}

Is this non standard code? A bug with LLVM? Or is there just a better way to accomplish the same task? Note: The function pointer must come first in the template so that the function information can be deduced automatically.

  • Looks like a pretty unnecessary way to say `std::bind`. – chris Apr 14 '13 at 21:03
  • std::bind doesn't give me something I can use as a function pointer. The Python binding api requires I give it function pointers of a uniform signature. – Phantom5800 Apr 14 '13 at 21:07
  • Oops, I missed that part. It's a pity, since that or variadic templates are perfect depending on your needs. – chris Apr 14 '13 at 21:10
  • 1
    Wow, gcc 4.7 crashes while compiling this snippet. BTW: `reinterpret_cast`ing a function that takes one argument, to a function type that takes no arguments is probably UB. – mfontanini Apr 14 '13 at 21:13
  • UB? It should be safe as long as it is casted back to the right type before using it, as with using reinterpret_cast for anything. g++ 4.2 complains that it can't do the cast because a function pointer cast isn't a constant expression ... which doesn't make sense to me. Another case where Microsoft will compile something that it probably shouldn't – Phantom5800 Apr 14 '13 at 21:24

1 Answers1

3

Clang is correct. I believe 14.3.2p1 rules out this:

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, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or

The important part is expressed (ignoring parentheses) as & id-expression. The expression must have an &, however you cannot take the address of an rvalue. So this pretty much rules out any casts.

Also, from 5.19p2 reinterpret_cast is illegal in constant expressions:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression

— a reinterpret_cast (5.2.10);

Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • That is really annoying, do you know of an alternate solution to what I am trying to do? – Phantom5800 Apr 14 '13 at 21:55
  • I'm not exactly sure what your use is, but maybe [this question might help](http://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer). – Jesse Good Apr 14 '13 at 22:06
  • Sadly it's not exactly what I need. My goal is to wrap any function into a uniform signature that can be given to (currently) the cpython api to allow python scripts to call c++ functions in my game engine. And python doesn't give any kind of "user data" option when calling a function. – Phantom5800 Apr 14 '13 at 22:32