【问题标题】:C++ replacing member variables with values from other typesC++ 用其他类型的值替换成员变量
【发布时间】:2012-01-26 22:14:15
【问题描述】:

例如,我有一个包含 n 个成员变量的类 T

class T{
  ushort name;
 ushort id;
 double value;
.....etc...
};

我还有一个类 T1、T2.... 的集合,每个类都由成员变量组成 它们是 T 的成员变量的子集(由于没有更好的词,让我称之为 这是 T 的子集类型)。例如,T1 可能是

class T1 {
 ushort name;
 double value;
};

它只选择了 T 的两个成员。

我想写一个方法

template <typename X> 
T join(T t, X x)

我们返回一个类型为 T 的类,通过将 t 中每个成员变量的值替换为 x 的值(假设 X 是 T 的子类型),t 的其他值保持不变。

我可以考虑通过专业化来做到这一点。但是应该有一个优雅的方法来做到这一点(也许检测类型 X 何时是 T 的子集类型并做正确的事情)。

【问题讨论】:

    标签: c++ templates types


    【解决方案1】:

    我可以考虑通过专业化来做到这一点。但是应该有一种优雅的方法来做到这一点(也许检测类型 X 何时是 T 的子集类型并做正确的事情)。

    “检测”是专业化的一部分。您应该为“子集”类型提供特化,并且不提供泛型特化的实现(当有人使用该方法使用其他类型时引发编译错误)。

    【讨论】:

      【解决方案2】:

      如果您不想为所有子集类型提供专业化。您可以尝试使用成员检测成语:Member Detector,如果您使用的是 MSVC,则可以使用 __if_exist。 所以你只需要写 [number of members in T] * 2 宏(如果使用 MSVC,你不需要 SetXXX)而不是专门化 T 中所有可能的成员组合

      CREATE_MEMBER_DETECTOR(name);
      CREATE_MEMBER_DETECTOR(id);
      CREATE_MEMBER_DETECTOR(value);
      ......
      
      template<int N, typename T, typename R>
      class SetName
      { 
      public:
         void operator()(T& t, R& r)
         {
         }
      };
      
      template<typename T, typename R>
      class SetName<1, T, R>
      {
      public:
         void operator()(T& t, R& r)
         {
            t.name = r.name;
         }
      };
      ......
      (can be macros too)
      

      而 join() 应该是:

      template <typename SUBSET> 
      T join(T t, SUBSET x)
      {
         SetName<Detect_name<SUBSET>::value, T, SUBSET>()(t, x);
         SetValue<Detect_value<SUBSET>::value, T, SUBSET>()(t, x);
         ......
      
         return t;
      }
      

      【讨论】:

        【解决方案3】:

        我会实现从 T1...Tn 到 T 的转换(或者从 T 派生的某个类,并且具有实际设置了哪些成员的信息),然后根据 T 实现 join() 函数。不要想这实际上是模板魔术的好地方

        【讨论】:

          【解决方案4】:

          试试这个:

          #include <iostream>
          #include <typeifo>
          
          using namespace std;
          
          template<typename T>
          struct SetBase
          {
              T first;
              T second;
              SetBase(const T& first = T(), const T& second = T()) 
              : first(first), second(second)    {}
          };
          
          template<typename T>
          struct Set : public SetBase<T>
          {
             short name_id;
             Set(const T& first = T(), const T& second = T(), const short& name) :
             SetBase<T>(first, second), name_id(name){}
          };
          
          template<typename Class, typename BaseClass>
          Class* join(Class **a, BaseClass *b)
          {
              if(typeid(Class) != typeid(BaseClass))
              {
                  Class* retval = new Class(*static_cast<Class*>(b));
                  retval->name_id = (*a)->name_id;
                  *a = retval;
              }
              else
              {
                  Class* retval = new Class(*b);
                  *a = retval;
              }
              return retval;
          }
          
          int main()
          {
              Set<int> *a = new Set<int>(1, 2, 3);
              SetBase<int> *b = new SetBase<int>(4, 5);
              cout << join(&a, b)->first << " " << join(&a, b)->second << " " << join(&a, b)->name_id << "\n";
              cout << a->first << " " << a->second << " " << a->name_id << "\n";
          
              return 0;
          }
          

          Set 类是从 SetBase 派生的公共类,因此我使用的强制转换是有效的

          【讨论】:

          • 这在传递给 join() 2 个 SubSetClass 的 agruments 时不起作用
          猜你喜欢
          • 2021-09-02
          • 1970-01-01
          • 1970-01-01
          • 2021-12-06
          • 1970-01-01
          • 2014-07-20
          • 2021-02-19
          • 1970-01-01
          • 2011-09-11
          相关资源
          最近更新 更多