Consider the following example:
#include <utility>
#include <iostream>
struct bar
{
void baz() { std::cout << "bar::baz" << std::endl; }
};
template <typename Signature>
struct function_traits;
template <typename ReturnType, typename Class, typename ...ArgumentTypes>
struct function_traits<ReturnType (Class::*)(ArgumentTypes...)>
{
typedef ReturnType (Class::*Signature)(ArgumentTypes...);
typedef ReturnType (*FuncPtr)(void const *ip, ArgumentTypes&& ...);
template <Signature mf>
static ReturnType wrapper(void const *p, ArgumentTypes&& ...args)
{
Class* instance = const_cast<Class*>(static_cast<Class const *>(p));
return (instance->*mf)(std::forward<ArgumentTypes>(args)...);
}
};
template <typename Type>
constexpr auto wrap(Type p) -> typename function_traits<Type>::FuncPtr
{
return &(function_traits<Type>::template wrapper<p>); // ERROR: Address of overloaded function 'wrapper' does not match required type 'void (const void *)'
}
int main()
{
auto v = wrap(&bar::baz);
}
I’ve tested it with Xcode 4.5.2 – Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Do I want too much?
The parameter declaration
is incompatible with the template-name
Even in a
constexprfunction, a parameter cannot be used as a constant expression.Usually this error manifests itself as an attempt to adjust the
constexprfunction’s return type according to the value of the argument, but this is a little subtler since the type expression is part of the value computation, with the value always having the same type.The fundamental problem is that the template is being asked to do runtime work. You can decide what PTMF to call it with at runtime.
constexprnever restricts the arguments that may be passed to a function. (I.e., that a function may only be called with constant arguments.) It only makes the function a candidate for use in contexts where a constant is required.