I have the following class which wraps a member function:
#include <cstdio>
#include <type_traits>
#include <utility>
using namespace std;
class testclass {
public:
double get() { return d_; }
void set(double d) { d_ = d; }
double d_ = 0.0;
};
template<typename Retriever, Retriever retrieverFunc, typename Updater, Updater updaterFunc, typename OwningClass>
struct Wrapper {
Wrapper(Retriever retriever, Updater updater, OwningClass* owner) : retriever_(retriever), updater_(updater), containingClass_(owner) {}
using GetterReturnType = std::invoke_result_t<decltype(retrieverFunc), OwningClass>;
GetterReturnType Get() { return (containingClass_->*retriever_)(); }
template<typename...Args>
using SetterReturnType = std::invoke_result_t<decltype(updaterFunc), OwningClass, Args...>;
template<typename...Args>
SetterReturnType<Args...> Set(Args&&... args) { return (containingClass_->*updater_)((forward<Args>(args))...); }
Retriever retriever_;
Updater updater_;
OwningClass* containingClass_;
};
int main() {
testclass tc;
Wrapper<decltype(&testclass::get), &testclass::get, decltype(&testclass::set), &testclass::set, testclass> pp(&testclass::get, &testclass::set, &tc);
pp.Get();
pp.Set(1.0);
}
Clearly, the syntax for declaring a wrapper is a bit tedious, so I wanted to clean it up a bit. I tried this:
template<typename Retriever, Wrapper Updater, typename OwningClass>
using WrapperSimplified = Wrapper<decltype(Retriever), Retriever, decltype(Updater), Updater, OwningClass>;
with the intention of being able to say this:
WrapperSimplified<&testclass::get, &testclass::set, testclass> pp(&testclass::get, &testclass::set, &tc);
But it does not compile, VS2022 complains
'Retriever': is not a valid type for non-type template parameter 'retrieverFunc'
How can I achieve this please?
CodePudding user response:
Retriever
is supposed to be the value, not the type, of the non-type template argument. So it should be declared as non-type template parameter. Since you want the type to be deduced, the type of the non-type template parameter should be auto
. Equivalently for Updater
:
template<auto Retriever, auto Updater, typename OwningClass>
using WrapperSimplified = Wrapper<decltype(Retriever), Retriever, decltype(Updater), Updater, OwningClass>;
But from what I can tell the class doesn't actually use the non-type template parameters retrieverFunc
and updaterFunc
. You can remove them (replacing the decltype(retrieverFunc)
with Retriever
and decltype(updaterFunc)
with Updater
).
Then the class object can be created simply using CTAD:
Wrapper pp(&testclass::get, &testclass::set, &tc);