如果我没有使用正确的术语,请提前道歉。
我希望有2个具有相同名称的函数,一个在值为左值时调用,另一个在不是左值时调用。例如:
typedef void (*fn_t)();
void fn() { }
fn_t pFn = fn;
fn_t* distinguish(fn_t pFn)
{
return pFn;
}
// NOTE: Will not work
fn_t*& distinguish(fn_t& pFn)
{
return pFn;
}
fn_t*& distinguish1(fn_t& pFn)
{
return pFn;
}
int main()
{
// call the one that takes a parameter from which I cannot get the address of the function pointer
distinguish(fn);
fn_t pFn = fn;
// call the one that takes a parameter from which I can get the address of the function pointer
distinguish(pFn);
distinguish1(pFn); // this will work
distinguish1(fn); // this will not work
return 0;
}
这可能吗?也许我可以使用SFINAE?
我正在使用弯路而且我发现他们使用的演员非常难看,所以我已经写了几个模板函数来为我做演员。
// Cast a function pointer to a void *
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(RET_TYPE(WINAPI * pOriginalFunction)(ARGs...))
{
return (void*)pOriginalFunction;
}
// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrRefToVoidPtrRef(RET_TYPE(WINAPI*& pOriginalFunction)(ARGs...))
{
return (void*&)pOriginalFunction;
}
这允许我进行以下调用:
BOOL (WINAPI *pDestroyIcon)(HICON) = DestroyIcon;
DetourAttach(&fnPtrRefToVoidPtrRef(pDestroyIcon), fnPtrToVoidPtr(DestroyIcon));
但是,我想知道是否可以将两个函数名称fnPtrRefToVoidPtrRef
和fnPtrToVoidPtr
合并为一个名称。
执行以下操作并不起作用,因为它无法推断出模板参数:
// Cast a function pointer to a void *
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(RET_TYPE(WINAPI * & pOriginalFunction)(ARGs...))
{
return (void*)pOriginalFunction;
}
// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrToVoidPtr(RET_TYPE(WINAPI * && pOriginalFunction)(ARGs...))
{
return (void*&)pOriginalFunction;
}
BOOL (WINAPI *pDestroyIcon)(HICON) = DestroyIcon;
void* p1 = fnPtrToVoidPtr(DestroyIcon);
void** p2 = fnPtrToVoidPtr(pDestroyIcon);
但是这会导致以下错误:
// error C2784: 'void *&`anonymous-namespace'::fnPtrToVoidPtr(RET_TYPE (__stdcall *&&)(ARGs...))' : could not deduce template argument for 'overloaded function type' from 'overloaded function type'
使用我原来的功能,这很好用:
BOOL (WINAPI *pDestroyIcon)(HICON) = DestroyIcon;
void* p1 = fnPtrToVoidPtr(DestroyIcon);
void** p2 = &fnPtrRefToVoidPtrRef(pDestroyIcon);
答案 0 :(得分:2)
// Cast a function pointer to a void *
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(RET_TYPE(WINAPI *&& pOriginalFunction)(ARGs...)) {
return (void*)pOriginalFunction;
}
// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrToVoidPtr(RET_TYPE(WINAPI*& pOriginalFunction)(ARGs...)) {
return (void*&)pOriginalFunction;
}
我认为你想要什么。 rvalue获得&&
左值&
并且未检测到歧义。
现在上面的缺点是&&
案例不会正确推断签名。我可以弄清楚如何,或者我可以使用蛮力来避免这个问题。我们将两者移动到details
命名空间,我们添加标签类型以在两者之间进行分派,我们删除&&
,然后我们添加一个调度函数,如下所示:
namespace details {
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(std::true_type, RET_TYPE(WINAPI * pOriginalFunction)(ARGs...)) {
return (void*)pOriginalFunction;
}
// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrToVoidPtr(std::false_type, RET_TYPE(WINAPI*& pOriginalFunction)(ARGs...)) {
return (void*&)pOriginalFunction;
}
}
template<class T>
auto fnPtrToVoidPtr(T&& t)
-> decltype(
details::fnPtrToVoidPtr(
std::is_rvalue_reference<T&&>{}, std::forward<T>(t)
)
) {
return
details::fnPtrToVoidPtr(
std::is_rvalue_reference<T&&>{}, std::forward<T>(t)
);
}
是的,多么糟糕。
要使上述工作正常,如果&foo
是函数名称,则需要传入foo
。如果仅传入foo
,则无法编译。如果需要,您可以编写一个将R(&)(Args...)
映射到R(*)(Args...)
的适配器,或以其他方式修复该怪癖。
答案 1 :(得分:1)
这里唯一的问题是你弄乱了你的typedef使用的间接数量。我已在this associated sample中解决了该问题。
简而言之,它之所以不起作用,是因为你选择了fn_t*&
。值pFn
仅为fn_t
,而非fn_t*
。这就是参考不能引用它的原因。由于fn_t
已包含指针部分,因此您无需向其添加其他指针。
答案 2 :(得分:0)
修改:您在这里不需要std::forward
,但它只是为了展示更多&#34;透明&#34;通过函数的值的视图。
使用&amp;和&amp;&amp;在需要的时候,&amp; =左值和&amp;&amp; = rvalue。
http://coliru.stacked-crooked.com/a/81539ac10b8be5a1
#include <iostream>
#include <utility>
int& forward(int& i)
{
std::cout << "lvalue: ";
return std::forward<int&>(i);
}
int&& forward(int&& i)
{
std::cout << "rvalue: ";
return std::forward<int&&>(i);
}
int*&& forward(int*&& ptr_i)
{
std::cout << "rvalue ptr: ";
return std::forward<int*&&>(ptr_i);
}
int*& forward(int*& ptr_i)
{
std::cout << "lvalue ptr: ";
return std::forward<int*&>(ptr_i);
}
const int* forward(const int* const ptr_to_const)
{
std::cout << "const ptr to lvalue: ";
return std::forward<const int* const>(ptr_to_const);
}
int main()
{
int i = 1;
const int j = 13;
int* ptr_i = &i;
const int * const const_ptr_const_i = &j;
int * const const_ptr_i = &i;
std::cout << forward(0) << std::endl;
std::cout << forward(i) << std::endl;
std::cout << forward(ptr_i) << std::endl;
std::cout << forward(&i) << std::endl;
//These two are almost the same by nature; note the variables they point to are different.
std::cout << forward(const_ptr_const_i) << std::endl;
std::cout << forward(const_ptr_i) << std::endl;
std::cout << "Cannot have a const pointer to a const rvalue because you can't really have a const pointer to a temporary/disappearing/ephermal rvalue." << std::endl;
return 0;
}