存储成员的获取/设置功能以供以后使用

问题描述

我想存储一对成员get / set函数,以便以后与T类型的对象一起使用。

我有部分工作设置,请参见下文。问题仍然存在:

  • 我如何(智能)处理所有可能的变体? member_get可能是[返回值或const值&甚至是value&| const或非const] member_set可以是[接受const&,&或&&]。当然,“最佳实践”会排除某些组合,但是我不能依靠它,因为对member_get和member_set的定义已不复存在。

  • 我如何正确处理可能的member_set移动语义?

  • 是否有其他/更好/更简单的通用方法解决此问题?

注意:

  • 我特意留下了二传手的确切类型S。不知道这是个好主意。
  • Lambda很明显浮现在脑海中,但我看不到它们如何帮助解决这个问题。 Make( get,set )调用方不应该提供lambda。那只是将问题委托给他!?
  • 由于开销太大,应该排除所有std :: function想法
template <typename T,typename V,typename G,typename S>
class GetSet
{
public:

    constexpr GetSet( G member_get,S member_set ) : Get( member_get ),Set( member_set )
    { }

    auto GetValue( const T& t ) const 
    {
        return ( t.*Get )( );
    }

    void SetValue( T& t,V&& value ) const
    {
        ( t.*Set )( std::forward<V>( value ) );
    }

private:
    G               Get;
    S               Set;
};

template <typename T,typename ValueType,typename S>
constexpr auto Make( ValueType( T::*member_get )( ) const,S member_set )
{
    using G = ValueType( T::* )( ) const;
    return GetSet<T,ValueType,G,S>( member_get,member_set );
}

解决方法

不确定为什么需要这样做,但是最简单的解决方案如下。

#include <utility>

template <class F> struct ClassType;

template <typename Ret,typename TCls,typename... Args>
struct ClassType<Ret (TCls::*)(Args...)> {
    using type = TCls;
};

template <typename Ret,typename TCls>
struct ClassType<Ret (TCls::*)() const> {
    using type = TCls;
};


template<class TFnGet,class TFnSet>
class GetSet
{
   public:
      using TGet = TFnGet;
      using TSet = TFnSet;
   public:
      inline GetSet(TGet fnGet,TSet fnSet)
         : m_fnGet(fnGet),m_fnSet(fnSet)
      {
      }

      template<class T>
      inline decltype(auto) GetValue(T&& r) const
      {
         static_assert(std::is_same<typename std::remove_cv<typename std::remove_reference<T>::type>::type,typename ClassType<TFnGet>::type>::value,"wrong type of r?");
         return (r.*m_fnGet)();
      }

      template<class T,class TValue>
      inline void SetValue(T&& r,TValue&& value)
      {
         static_assert(std::is_same<typename std::remove_cv<typename std::remove_reference<T>::type>::type,typename ClassType<TFnSet>::type>::value,"wrong type of r?");
         (r.*m_fnSet)(std::forward<TValue>(value));
      }

   private:
      TGet m_fnGet;
      TSet m_fnSet;
};


template<class TGet,class TSet>
GetSet<TGet,TSet> MakeGetSet(TGet fnGet,TSet fnSet)
{
   static_assert(std::is_same<typename ClassType<TGet>::type,typename ClassType<TSet>::type>::value,"members of different classes?");
   return GetSet<TGet,TSet>(fnGet,fnSet); 
}

已验证:

class A
{
   public:

   void Set(int i) {}
   int Get() const { return 0;}
   
   void SetRef(char& ch) {}
   A& GetRef() { return *this;}
   
   void SetRRef(float&& ) {}
   int&& GetRRef() { return 1; }

   void SetConstRef(const char& ch) {}
   int GetNotConst() { return 0;}
};


int main(int argc,char* argv[])
{
   A a;

   auto gs = MakeGetSet(&A::Get,&A::Set);
   auto gsRef = MakeGetSet(&A::GetRef,&A::SetRef);
   auto gs2 = MakeGetSet(&A::GetRRef,&A::SetRRef);
   auto gsNonConst = MakeGetSet(&A::GetNotConst,&A::SetConstRef);

   int x = gs.GetValue(a);
   gs.SetValue(a,2);
   const A& ra = a;
   x = gs.GetValue(ra);

   A& r = gsRef.GetValue(a);
   char ch =' ';
   gsRef.SetValue(a,ch);
   
   x = gs2.GetValue(a);
   gs2.SetValue(a,1.1f);
   
   x = gsNonConst.GetValue(a);
   gsNonConst.SetValue(a,ch);

   std::cout << "ok\n";
   return 0;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...