模板结构为数组

时间:2017-09-25 00:32:10

标签: c++ arrays templates struct types

是否可以使用模板类型字段创建结构数组?

template<typename T>
struct MyStruct {
    T *pField;
};

MyStruct< ?? > mystruct_arr[] = {
        { pFieldOfType1 },
        { pFieldOfType2 },
};

以上显然不起作用,但是可以使用其他技术吗?

我试图遍历数组mystruct_arr并在每个结构行上调用此函数:

template<typename T>
void SetupField(T &pSourceField, ...)
{
    Base *field = ...->findBaseFieldFromDatabase(...);
...
    pSourceField = static_cast<T>(field);
...
}

原因是尝试重构一段非常重复的代码,我必须根据一些不同的参数static_cast一长串不同类型的代码,而不会让它过于复杂。

2 个答案:

答案 0 :(得分:2)

模板不是classstruct。对于在模板实例化时创建的classstruct,可以将其视为蓝图或配方。

通过指定所需的模板参数,模板只有在实例化时才会变为实际classstruct

MyStruct<int>

现在你有一个实际的,活的,呼吸的class。但是MyStruct<int>MyStruct<char>完全不同。如果不指定模板参数,MyStruct不是类,结构或任何占用单个字节RAM的内容。它只是某些structclass的模板。

但是对于模板参数,例如MySutrct<int>,这变成了一个包含字段和方法的实际类。现在你有了一个类,你现在可以拥有一组这些,现在:

MyStruct<int> mystruct_arr[] = {

};

或者您可以使用不同的MyStruct<char> s数组:

MyStruct<char> mystruct_arr2[] = {

};

但是你不能拥有一个包含这两个数组的数组,其原因相同,准确,精确,你不能拥有一个包含不同类型和类的自助餐的单个数组。您不能拥有包含charint s,float,指针或各种类的数组。数组始终包含相同类型/类的值。因此,选择一个特定的MyStruct<whatever>,并从中制作一个阵列,这就是你所能做的一切。

但是你现在也可以声明另一个结构:

struct many_structs {
     MyStruct<int> int_struct;
     MyStruct<char> char_struct;

     // ...
};

这种开始看起来像你想要的数组。但它不是一个阵列。它只是一个普通的struct;而不是使用数组索引来访问特定的模板实例,您可以直接引用结构成员。

您可以通过一些额外的工作为您的结构专门设置std::get,并使此结构看起来像一个数组。但是现在你意识到你重新发明了std::tuple,并且可以简单地做到这一点:

std::tuple<MyStruct<int>, MyStruct<char>> mystruct_tuple;

最后,通过声明包含std::any的数组,只能通过一些额外的工作,以及支持C ++ 17的C ++编译器,最接近您尝试做的事情,或许std::variant。如果数组应该只包含有限的枚举模板实例,std::variant提供最大的类型安全性和方便性:

std::variant<MyStruct<int>, MyStruct<char>> mystruct_arr[]={

};

结果数组仅包含这两个特定的模板实例。使用std::any时,螺丝会进一步松动,但您必须做更多的工作才能使用和访问数组中的每个值。

答案 1 :(得分:1)

您认为您需要一系列模板。

你真正想要的是一组你可以称之为特定模板功能的类型。

第一种是不可能的。第二种在C ++中称为类型擦除。

template<class T>
using setup_fptr=void(*)(T &, Foo)
using gen_setup_ptr=void(*)(void*, Foo);

template<class T>
setup_ptr<T> get_setup(){ return SetupField<T>; }
template<class T>
gen_setup_ptr get_gen_setup(){
  return [](void* p, Foo f){ get_setup<T>( *static_cast<T*>(p), f ); };
}
struct can_setup {
  void* ptr=0;
  gen_setup_ptr f=0;

  can_setup(can_setup const&)=default;
  can_setup& operator=(can_setup const&)=default;
  can_setup()=default;
  explicit operator bool() const{return f;}

  template<class T>
  can_setup(T* pt):
    ptr(pt),
    f( get_gen_setup<T>() )
  {}
  void setup( Foo foo ) const {
    f(ptr, foo );
  }
};

存储can_setup的数组。循环遍历他们,呼叫.setup(foo)

Foo是您正在使用的其他任何args的占位符。

这种技术被称为类型擦除;我们忘记(擦除)T的所有内容,但我们可以setup