Функция шаблона, принимающая универсальный указатель на функцию-член для реализаций как const, так и по значениям - PullRequest
0 голосов
/ 11 октября 2019

, я хочу иметь шаблонную функцию, которая принимает унарные указатели на функции-члены экземпляра некоторого универсального типа. Моя проблема заключается в том, что я должен поддерживать функции-члены void (T val) и void (const T & val).

Я написал одну шаблонную функцию для каждого случая, и она отлично работает, но это приводит к дублированию кода, посколькуфункциональная логика полностью одинакова. (Я нашел нечто совершенно похожее здесь: Функция, принимающая и указатель на функцию-член, и указатель на константную функцию-член , но я не вижу окончательного решения).

Пример сущностиУ меня есть это:

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

Isесть какой-то способ определить эту функцию один раз и сказать:


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

}

1 Ответ

0 голосов
/ 14 октября 2019

Благодаря подсказке Игоря Тандетника мне удалось составить решение. 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);

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...