首页 > 解决方案 > 模板函数采用指向具有 const& 和按值实现的成员函数的通用指针

问题描述

我想要一个模板函数,它接受一些泛型类型的实例的一元成员函数指针。我的问题是我必须同时支持 void(T val) 和 void(const T& val) 成员函数。

我为每种情况编写了一个模板函数,它工作正常,但这会导致代码重复,因为函数逻辑完全相同。(我在这里发现了完全相似的东西:函数同时使用指向成员函数的指针和指向 const 成员函数的指针,但我没有看到明确的解决方案)。

上面提到的泛型类型的一个例子:

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;}
};

UserAddress我想通过引用传递一些重型类型在哪里。

我的模板函数:

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)
    {
...
    }
};

有没有办法定义这个函数来支持以下内容:


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);
   
}

标签: c++11templatesmember-function-pointers

解决方案


感谢Igor Tandetnik的提示,我设法编译了一个解决方案。std::enable_if不是我需要的,因为我不需要停用过载(或者至少我无法使用它找到解决方案)。 std::conditional成功了。

这是代码:

#include <string>
#include <functional>
#include <map>
#include <string>
#include <type_traits>

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;}
};

template <typename TPersistentObject>
class Persistence
{
public:
    std::map<std::string, std::function<void(TPersistentObject*)>> mSetterOfProperty;

    template <typename TPropertyValue>    
    void DefinePropertySettingMethod(const std::string& propertyName,
                                     void (TPersistentObject::*propertySetter)(TPropertyValue), 
                                     std::function<
                                             typename std::conditional<!std::is_same<TPropertyValue, typename  std::decay<TPropertyValue>::type>::value,
                                             typename std::decay<TPropertyValue>::type, TPropertyValue>::type
                                     (void)> dataReader)
    {
            mSetterOfProperty[propertyName] =
                [propertySetter, dataReader](TPersistentObject* persistentObject) 
            {
                (persistentObject->*propertySetter)(dataReader());
            };
    }
};


int main()
{

    std::function<int()>  intDataReader = []() {
        return 1;
    };

    std::function<std::string()>  stringDataReader = []() {
        return UserAddress("Next Door");
    };

  Persistence<User> p;
  p.DefinePropertySettingMethod("Height", &User::SetHeight, intDataReader);
  p.DefinePropertySettingMethod("Address", &User::SetAddress, stringDataReader);

}

推荐阅读