I'm making a hooking library, which basically intercepts a function and makes it jump to the intercept function.
class CHook
{
public:
template<typename S, typename D>
void SetupHook(S Source, D Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)Destionation;
}
private:
PBYTE pSource;
PBYTE pDestination;
};
I want CHook::SetupHook to take (for Destination) either DWORD (address of function), function pointer which both can be type casted to PBYTE.
I want CHook::SetupHook to also be able to take a function pointer from lambda but it cannot be type casted to PBYTE so I overload it and since I know lambda function are classes I use std::is_class to identify them.
template<typename S, typename D>
void SetupHook(S Source, typename std::enable_if<!std::is_class<D>::value, D>::type Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)Destionation;
}
template<typename S, typename D>
void SetupHook(S Source, typename std::enable_if<std::is_class<D>::value, D>::type Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)to_function_pointer(Destionation);
}
But it results in these erorrs:
error C2783: 'void CHook::SetupHook(S,std::enable_if<std::is_class<D>::value,D>::type)': could not deduce template argument for 'D'
note: see declaration of 'CHook::SetupHook'
When you write code like:
template <typename S, typename D>
void SetupHook(S Source, typename std::enable_if<!std::is_class<D>::value, D>::type Destionation)
{
// (...)
}
you make D
a non-deducible type template parameter. That is, a type template parameter list, <typename S, typename D>
, does not correspond to the parameter list of a function, and so, the compiler can't tell which type template parameter it is supposed to deduce in place of
typename std::enable_if<!std::is_class<D>::value, D>::type
Formally, a nested name specifier introduces a non-deduced context .
The solution is let the compiler deduce D
, as a plain parameter type, and to put std::enable_if
elsewhere, eg:
template <typename S, typename D>
typename std::enable_if<!std::is_class<D>::value>::type SetupHook(S Source, D Destionation)
{
// (...)
}
Now, the compiler sees that D
is the type of the second argument expression.
Kind of a hack-y trick, but you can convert a lambda to a function pointer using unary+. Note that you can't convert a lambda to a function pointer if it captures any variables.
template<typename S, typename D>
void SetupHook(S Source, D Destionation)
{
pSource = (PBYTE)Source;
// static_cast is required for avoiding Visual Studio bug
pDestination = (PBYTE)+static_cast<void(*)()>(Destionation);
}
...
void some_func() {}
int main() {
auto str = "hello";
auto some_lambda = [](){};
auto some_capturing_lambda = [=]() {
std::cout << str;
};
SetupHook(str, some_func); // Works
SetupHook(str, some_lambda); // Works
SetupHook(str, some_capturing_lambda); // Error in Unary Expression
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.