12

我正在使用模板函数进行对象构造以从反射数据创建对象,并且效果很好,但是现在我想在反射系统中支持 STL 容器类型,以便对象,例如:

// Note - test case only
// for real world usage it would probably not be structured like this 
// and the phrases would be mapped by an id or something 
struct Phrases {
  std::vector<std::string> phrases;
};

typedef std::string Lang;
struct Langs {
  std::map< Lang, Phrases > translations;
};

可以支持。我可以在返回时做一些正则表达式魔术

typeid( object ).name() 

确定对象是向量还是映射,以及对象的参数参数是什么。我已经尝试了一些模板魔术来执行以下操作,其中 CreateString、ConstructString 和 DestroyString 位于函数中,而数据也位于更复杂的东西中,它使用类型数据库来处理对象构造。

// Representational of code, basically a copy-paste to a different test project where I can work out the problems with this specific vector problem 
// Vector specialised construction 
template <typename T> void ConstructVector( void* object, const std::vector<std::string>& data ) {
  T* vec = (T*)object;
  Name vector_type = GetVectorTypeName<T>();

  void *obj; 
  CreateString(&obj);
  // All fields in this type should be valid objects for this vector 
  for( std::vector<std::string>::const_iterator it = data.begin(), end = data.end(); it != end; ++it ) {
    // Push it 
    vec->push_back(*obj);
    // Get address to new instance 
    void *newly = &vec->back(); 
    ConstructString(newly,*it);
  }
  DestroyString(&obj);

}

由于“vec->push_back(*obj);”的非法间接,这不起作用 我不能这样,因为我实际上并不知道类型。基本上我需要做的是创建这个向量,其中已经有一些空白的未设置元素,或者在没有实际类型的情况下向它添加新元素,因为如果我可以获得指向向量内的内存块的指针,我可以滚动并构建对象。但是向量添加要求,例如

vector::push_back( T& value ) 

或者

vector::insert( Iter&, T& ) 

除非我能从模板内部得到那个 T 类型,否则对我不起作用

测试代码的 pastebin 来尝试解决这个问题:http: //pastebin.com/1ZAw1VXg

所以我的问题是,当我在像这样的模板中时,如何获得 std::vector 声明的 std::string 部分

template <typename T> void SomeFunc() {

  // Need to get std::string here somehow       
  // Alternatively need to make the vector a certain size and then 
  // get pointers to it's members so I can construct them 
}


SomeFunc<std::vector<std::string>>>();
4

2 回答 2

28

有两种方法可以做到这一点。

1)要么您利用std::vector<>(像所有标准库容器类一样)维护一个成员类型这一事实value_type,它表示存储在向量中的元素的类型。所以你可以这样做:

template <typename T> void SomeFunc() {
  typename T::value_type s;  // <--- declares a `std::string` object
                             //      if `T` is a `std::vector<std::string>`
}

2)否则,您更改函数的声明并使用模板模板参数:

template <template <typename> class T, typename Elem>
void SomeFunc(T<Elem> &arg)
{
  Elem s;
}

但是,这样做有一个小问题:std::vector确实是一个带有两个参数(元素类型和分配器类型)的模板,这使得模板模板参数的使用有点困难,并且仍然保持语法简单。对我有用的一件事是声明向量类型的别名,它只留下一个模板参数:

template <typename Elem>
using myvector = std::vector<Elem>;

然后我可以SomeFunc这样使用:

int main()
{
  myvec<std::string> vec;
  SomeFunc(vec);
}
于 2012-09-19T07:54:25.047 回答
11

在 c++11 中,您可以使用 decltype 和 std::decay 来达到这种效果:

std::vector<int> vec; using T = typename std::decay<decltype(*vec.begin())>::type;

于 2018-11-12T10:14:57.563 回答