I want to have a template function which accepts unary member-function pointers of an instance of some generic type. My problem is that I must support both void(T val) and void(const T& val) member functions.
I have written one template function for each case and it works fine, but this leads to code duplication since the function logic is completely the same. (I found something completely similar here: Function taking both pointer to member-function and pointer to const member-function but I fail to see a definitive solution).
An example of the generic type mentioned above:
using UserAddress = std::string;
class User
{
private:
int mHeight;
UserAddress mAddress;
public:
void SetHeight(int height){mHeight = height;}
void SetAddress(const UserAddress& address){mAddress = address;}
};
Where UserAddress
is some heavy type I want to pass by reference.
My templated function:
template <typename TPersistentObject>
class Persistence
{
private:
std::map<std::string, std::function<void(User*)>> mSetterOfProperty;
template <typename TPersistentObject, typename TPropertyValue>
void DefinePropertySettingMethod(const std::string& propertyName,
void (TPersistentObject::*propertySetter)(TPropertyValue), std::function<TPropertyValue(void)> dataReader)
{
mSetterOfProperty[propertyName] =
[propertySetter, columnDataReader](TPersistentObject* persistentObject)
{
(persistentObject->*propertySetter)(dataReader());
};
}
};
/// Const& implementation leading to code duplication
template <typename TPersistentObject, typename TPropertyValue>
void DefinePropertySettingMethod(const std::string& propertyName,
void (TPersistentObject::*propertySetter)(const TPropertyValue&), std::function<TPropertyValue(void)> dataReader)
{
...
}
};
Is there some way to define this function to support the following:
int main()
{
auto intDataReader = []() {
return 1;
};
auto stringDataReader = []() {
return UserAddress("Next Door");
};
Persistence p;
p.DefinePropertySettingMethod<User,int>("Height", &User::SetHeight, intDataReader);
p.DefinePropertySettingMethod<User,UserAddress>("Address", &User::SetAddress, stringDataReader);
}