在编译时判断参数类型是否为void



请考虑这个成员函数包装器的简单示例。我已将此更新为更完整的代码,以帮助回答建议。

#include <cstring>
#include <utility>
using namespace std;
template <typename FunctionWrapperType>
struct THE_PROXY {
THE_PROXY(FunctionWrapperType* wrapper) : wrapper_(wrapper) {}
template<typename T>
THE_PROXY& operator=(T val) {
if constexpr (std::is_same_v<typename FunctionWrapperType::ARG_TYPE, void>) {
void* address_to_write_to = wrapper_->Set();
memcpy(address_to_write_to, &val, sizeof(val));
} else {
wrapper_->Set(val);
}
return *this;
}
private:
FunctionWrapperType* wrapper_;
};
template<typename Function, typename ContainingClass, typename ArgType>
struct FunctionWrapper {
FunctionWrapper(Function func, ContainingClass* c) : func_(func), containingClass_(c) {}
using ARG_TYPE = ArgType;
THE_PROXY<FunctionWrapper> operator*() { return THE_PROXY(this); }
private:
template<class T> friend struct THE_PROXY;
template<typename Arg>
void Set(Arg arg) { std::invoke(func_, containingClass_, arg); }
void* Set() { return std::invoke(func_, containingClass_); }
Function func_;
ContainingClass* containingClass_;
};

struct MyStruct2 {
void* Func() { return &n_; } 
void Func2(int n) { n_ = n; }  
private:
int n_;
};
int main() {
MyStruct2 ms;
FunctionWrapper<decltype(&MyStruct2::Func), MyStruct2, void> fw(&MyStruct2::Func, &ms);
FunctionWrapper<decltype(&MyStruct2::Func2), MyStruct2, int> fw2(&MyStruct2::Func2, &ms);
*fw = 100;  // This assignment will involve the memcpy update
*fw2 = 65; // This is plain and simply member update
}

现在,不可否认这有点奇怪。我基本上包装了一个API,它有两种更新成员变量的方式;当updatater函数不带参数时,它要求新值为返回地址的memcpyd;否则,updater函数将获取要写入的新值。

我当前根据我传递的模板类型ArgType确定调用哪个版本的Set()

如果我在operator=中不使用constexpr,我会得到关于

的编译错误
error C2672: 'invoke': no matching overloaded function found

…我认为这是因为if的两个分支都被编译,并且没有参数的Set()调用需要一个参数,所以显然我需要使用模板参数推导。我想知道的是,如果我能确定函数的参数类型是否为void,那么我就不需要手动将其作为参数传递。

请注意,有一些更新函数返回void*,但也接受一个参数,所以我不能简单地根据void*的返回类型确定这种行为。

这样的把戏存在吗?

使用专门化,您可以这样做:

template<typename MethodType>
struct FunctionWrapper;
// 1 arg
template<typename Class, typename ArgType>
struct FunctionWrapper<void (Class::*)(ArgType /*, ...*/) /* const volatile noexcept & && */>
{
using Function = void (Class::*)(ArgType);
FunctionWrapper(Function func) : func_(func) {}
Function func_;
};
// No args
template<typename Class>
struct FunctionWrapper<void (Class::*)(/*...*/) /* const volatile noexcept & && */>
{
using Function = void (Class::*)();
FunctionWrapper(Function func) : func_(func) {}
Function func_;
// special stuff.
};

在您的例子中,您可以检查method是否可调用,并去掉额外的模板参数:

template <typename FunctionWrapperType>
struct THE_PROXY {
THE_PROXY(FunctionWrapperType* wrapper) : wrapper_(wrapper) {}
template<typename T>
THE_PROXY& operator=(T val) { wrapper_->Set(val); return *this; }
private:
FunctionWrapperType* wrapper_;
};
template<typename Function, typename ContainingClass>
struct FunctionWrapper {
FunctionWrapper(Function func, ContainingClass* c) : func_(func), containingClass_(c) {}
THE_PROXY<FunctionWrapper> operator*() { return THE_PROXY(this); }
private:
template<class T> friend struct THE_PROXY;
template<typename Arg>
void Set(Arg arg)
{
if constexpr (std::is_invocable_v<Function, ContainingClass, Arg>) {
std::invoke(func_, containingClass_, arg);
} else {
void* address_to_write_to = std::invoke(func_, containingClass_);
memcpy(address_to_write_to, &arg, sizeof(Arg));
}
}
Function func_;
ContainingClass* containingClass_;
};

演示

最新更新