Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;模板化数据成员的替代方案_C++_Templates_Design Patterns_Containers_C++03 - Fatal编程技术网

C++ C++;模板化数据成员的替代方案

C++ C++;模板化数据成员的替代方案,c++,templates,design-patterns,containers,c++03,C++,Templates,Design Patterns,Containers,C++03,如果我有一个类DataManager: class DataManager { public: int getRecordInt( size_t i ) const; std::string getRecordString( size_t i ) const; private: std::vector<int> _vInt; std::vector<std::string> _vString; } 在我的实际应用程序中,我将有100多种数据

如果我有一个类
DataManager

class DataManager
{
 public:
   int getRecordInt( size_t i ) const;
   std::string getRecordString( size_t i ) const;

 private:
   std::vector<int> _vInt;
   std::vector<std::string> _vString;
}
在我的实际应用程序中,我将有100多种数据类型(除了int和std::string),因此我希望避免为每种类型编写单独的getter

现在,如果C++支持模板化变量名(它不),我可以将类实现为:

class DataManager
{
 public:
   template<typename T>
   T getRecord( size_t i ) const
   {
      return _v<T>[i];
   }

 private:
   std::vector<int> _v<int>;
   std::vector<std::string> _v<std::string>;
}
类数据管理器
{
公众:
模板
获取记录(大小)常数
{
返回v[i];
}
私人:
std::vector_v;
std::vector_v;
}
< C++ >

有什么办法可以达到目的吗?
(请注意,尽管我已将示例简化到最低限度,但我的实际问题要复杂得多,需要存在这样的
DataManager
类。)

如果您的类型只出现一次,您可以使用
std::tuple
std::get

class DataManager
{
public:
   template<typename T>
   T getRecord( size_t i ) const
   {
      return std::get<std::vector<T>>(v)[i];
   }

 private:
   std::tuple<std::vector<int>, std::vector<std::string>> v;
}
类数据管理器
{
公众:
模板
获取记录(大小)常数
{
返回std::get(v)[i];
}
私人:
std::元组v;
}
C++14解决方案: 你可以做的一件事是把所有不同的向量放到一个。然后可以使用指定从元组中获取哪个向量,然后访问该向量。那看起来像

class DataManager
{
 public:
   template<typename T>
   T getRecord( size_t i ) const
   {
      return std::get<std::vector<T>>(_v)[i];
   }

 private:
   std::tuple<std::vector<int>, std::vector<std::string>> _v{{1,2,3},{"a","b","c"}};
};

int main()
{
    DataManager d;
    std::cout << d.getRecord<std::string>(2);
}

不能使用模板化变量,但可以使用私有模板化方法返回适当的变量:

class DataManager
{
 public:
   template<typename T>
   T getRecord( size_t i ) const
   {
      return _v<T>()[i];
   }

 private:
   std::vector<int> _vInt;
   std::vector<std::string> _vString;
   template<typename T> std::vector<T>& _v() {
       throw std::logic_error("non managed type");
   }
};

template <> std::vector<int>& DataManager::_v<int>() {
   return _vInt;
}
template <> std::vector<std::string>& DataManager::_v<std::string>() {
   return _vString;
}
类数据管理器
{
公众:
模板
获取记录(大小)常数
{
返回v()[i];
}
私人:
std::vector _vInt;
std::vector_vString;
模板std::vector&_v(){
抛出std::逻辑_错误(“非托管类型”);
}
};
模板std::vector&DataManager::_v(){
回程时间;
}
模板std::vector&DataManager::_v(){
返回_v字符串;
}
这取决于您对您的实际用例是否是可接受的解决方案。

如果您的船不能浮起(我认为这是正确的处理方式),那么您可以咬紧牙关编写一个宏(C++03解决方案):

#定义添加记录类型(类型名、限定类型名)\
私人:\
std::vector _v##TYPENAME\
公众:\
限定的_TYPENAME get_record_35;#TYPENAME(size#ti)const{return_v#TYPENAME.at(i)}
类数据管理器
{
添加记录类型(字符串,标准::字符串)
添加记录类型(int,int)
};
#未定义添加记录类型

对于类DataManager的第二个假设实现,我可以简单地调用
intivalue=DM.getRecord(3)。我希望我的想法是明确的,我认为这是不可能的。它属于反射范畴,目前还不受支持。“模板化变量名”是什么意思?在您的上一个代码中,成员
\u v
std::vector
独立于
getRecord
的调用方式,它不清楚您在声明中使用
\u v
意味着什么,只是好奇您为什么要抛出异常而不是使用
静态\u assert
。由于调用将在编译时解决,“错误”不是更好吗?为每种类型编写单独的模板专门化是否比编写单独的getter更容易?@NathanOliver:可能是Java(此处错误)用法。。。我懒得构建它需要的
std::if
。如果您愿意,可以自由填写以编辑我的答案。@ChrisDrew:这取决于实际的用例。这就是我最后一句话的原因…@NathanOliver:而且C++03没有
static\u assert
:-)谢谢。这就是我想要的,但不幸的是,我只能在项目中使用C++03(在问题中忘了提到它),而且该版本的std::get()似乎是在C++14中引入的。如果你不能使用C++11/14,我想Serge Ballesta的答案是你必须这样做。或者你可以使用
boost
,它有
boost::tuple
。我担心tuple不可能保存“超过一百种数据类型”的答案,这与我写给Nathan的答案相同:谢谢你,你的解决方案就是我想要的,但不幸的是,我只能在项目中使用C++03(在问题中忘了提到它),这个版本的std::get()似乎是在C++14中引入的。在C++03中有什么想法吗?如果你有C++03,那么你就可以访问
tuple
type_traits
,这些都是实现
get
所需要的,这是相对容易的,事实上我很确定我曾经在cppreference.com上看到过一个实现示例。即使不是,我也作为我的后台库的一部分,直接从C++ C++ 14的建议中提取。您可能可以使用该代码作为基础。
c
class DataManager
{
 public:
   template<typename T>
   T getRecord( size_t i ) const
   {
      return _v<T>()[i];
   }

 private:
   std::vector<int> _vInt;
   std::vector<std::string> _vString;
   template<typename T> std::vector<T>& _v() {
       throw std::logic_error("non managed type");
   }
};

template <> std::vector<int>& DataManager::_v<int>() {
   return _vInt;
}
template <> std::vector<std::string>& DataManager::_v<std::string>() {
   return _vString;
}
#define ADD_RECORD_TYPE(TYPENAME, QUALIFIED_TYPENAME) \
private: \
    std::vector<QUALIFIED_TYPENAME> _v##TYPENAME; \
public:  \
    QUALIFIED_TYPENAME get_record_##TYPENAME(size_t i) const{return _v##TYPENAME.at(i);}

class DataManager
{
    ADD_RECORD_TYPE(string, std::string)
    ADD_RECORD_TYPE(int, int)
};
#undef ADD_RECORD_TYPE