C++ 具有可变成员数的结构或类
我想创建一个结构/类,该结构/类具有可变数量的类成员,这些成员可以在编译阶段决定(就像在模板元编程中所做的那样) 示例:假设类型和变量名都要指定,比如类型T1变量名应该是varName1等等……C++ 具有可变成员数的结构或类,c++,templates,metaprogramming,C++,Templates,Metaprogramming,我想创建一个结构/类,该结构/类具有可变数量的类成员,这些成员可以在编译阶段决定(就像在模板元编程中所做的那样) 示例:假设类型和变量名都要指定,比如类型T1变量名应该是varName1等等…… template <class T1 (varName1) > MyClass { T1 varName1; } template <class T1 (varName1), class T2 (varName2) > MyClass { T1 varNa
template <class T1 (varName1) >
MyClass
{
T1 varName1;
}
template <class T1 (varName1), class T2 (varName2) >
MyClass
{
T1 varName1;
T1 varName2;
}
模板
类名
{
T1 varName1;
}
模板
类名
{
T1 varName1;
T1 varName2;
}
在主代码中,可以像下面这样声明,或者以其他方式指定类型和名称
MyClass Obj
MyClass::somefunc()可以访问变量名
如下
MyClass::somefunc()
{
std::cout <<" abc value : " << abc << std::endl;
std::cout <<" xyz value : " << xyz << std::endl;
}
MyClass::somefunc()
{
std::cout模板不能指定变量名。如果您在编译时决定类中包含什么,您应该能够直接在源代码中指定它
你可以用一些宏来完成你想要的,但我不敢冒险进入这个黑暗的领域。你不能用模板指定名称,只能用类型或某些类型的值。你可以用宏来完成,但是在语言中尝试做太多的事是一个陷阱,我已经陷入了太多的陷阱她的路径可能对你有用:代码生成
考虑编写一个脚本,读入一些配置文件并写出类的定义。将脚本添加到构建过程中。这可能比模板元编程或宏skulduggery的黑魔法更容易维护和理解
python是我在脚本中使用的东西,每个类的配置都是一些易于解析的东西,比如json,但这些都是次要问题
在我当前的项目中,我们有数千行生成的文件,分布在100多个文件中……这些生成脚本被相对定期地修改,而且没有任何痛苦。我记得安德烈·亚历山德雷斯库(Andrei Alexandrescu)在他的书《现代C++》中描述了类似的内容.我这里没有副本,所以我不能确切地说出它是什么,在哪里
正如其他人所指出的,不可能将名称作为模板参数,但他创建了一个可以访问的结构,如data.get()
或类似的东西。如果有一种类型的多个数据,您可以执行data.get()
也许这会有帮助。您可以做类似的事情,但它们不会有不同的名称:
template <class T, int num_t >
MyClass
{
T var[num_T];
};
模板
类名
{
T var[num_T];
};
这忽略了边界检查,但这是另一回事。不可能如前所述。您可以使用boost的预处理器库获得等效的功能
最终,你所要求的不同于简单地说
struct Members
{
int a_;
double b_;
};
…变成
template <class Members>
class Add_Stuff : public Members
{
public:
doSomething() { ... };
};
……可以生成一些C++代码ala.…/p>
std::ostringstream streaming;
streaming << " void somefunc() const\n{\n std::cout ";
cout << "class " << class_name << "\n{\n";
while (cin.getline(type) && cin.getline(identifier))
{
cout << " " << type << ' ' << identifier << '\n';
streaming << "<< \"" << identifier << " \" << identifier << "\n ";
}
cout << " public:\n" << streaming.str() << "\n"
"};\n";
std::ostringstream流媒体;
流Loki的类型列表。
对我来说很复杂。但是我想你想要的东西可以用这个来完成。看看
这允许任意数量的数据元素(但在编译时是固定的),并允许对每个索引进行类型安全访问。我发现这个问题没有明确说明,不清楚目的是什么
序列化,我会考虑。
对于命名的、严格类型的可选参数,一种可能是使用,另一种更简单的可能是使用。它本质上是一组宏,通过一些不可穿透的内部模板黑魔法,生成像您所要求的类。我在Dobbs博士期刊上写了一篇关于它的文章,但下面是一个说明mai的使用示例n优点是,生成的选项类可以与另一个类层次结构并行扩展:
#include <iostream>
#include <progrock/cppx/arguments/options_boosted.h>
struct AbstractButton
{
// These members are not part of the cppx options scheme: in actual
// usage you will instead have e.g. some API level widget states.
int hTextAlign;
int vTextAlign;
int buttonPlacement;
// Defines a local class 'Options' with specified options & defaults.
CPPX_DEFINE_OPTIONCLASS( Options, CPPX_OPTIONS_NO_BASE,
( hTextAlign, int, 0 )
( vTextAlign, int, 0 )
( buttonPlacement, int, 0 )
)
explicit AbstractButton( Options const& params = Options() )
: hTextAlign( params.hTextAlign() )
, vTextAlign( params.vTextAlign() )
, buttonPlacement( params.buttonPlacement() )
{}
};
struct CheckBox: AbstractButton
{
bool isAuto;
bool is3State;
// Defines an extension of the base class' 'Options' class.
CPPX_DEFINE_OPTIONCLASS( Options, AbstractButton::Options,
( isAuto , bool, true )
( is3State, bool, false )
)
explicit CheckBox( Options const& params = Options() )
: AbstractButton( params )
, isAuto( params.isAuto() )
, is3State( params.is3State() )
{}
};
void show( CheckBox const& cb )
{
std::cout
<< std::boolalpha
<< "hTextAlign = " << cb.hTextAlign
<< ", isAuto = " << cb.isAuto << ".\n";
}
int main()
{
typedef CheckBox::Options CBOptions;
CheckBox widget1;
show( widget1 ); // 0, true (the default values)
CheckBox widget2( CBOptions().hTextAlign( 1 ) );
show( widget2 ); // 1, true
CheckBox widget3( CBOptions().hTextAlign( 1 ).isAuto( false ) );
show( widget3 ); // 1, false
}
#包括
#包括
结构抽象按钮
{
//这些成员不是cppx期权计划的一部分:实际上
//相反,您将拥有一些API级别的小部件状态。
int-hTextAlign;
int-vTextAlign;
int按钮位置;
//使用指定的选项和默认值定义本地类“Options”。
CPPX_定义_选项类(选项、CPPX_选项、无基础、,
(hTextAlign,int,0)
(vTextAlign,int,0)
(按钮位置,int,0)
)
显式抽象按钮(Options const¶ms=Options())
:hTextAlign(params.hTextAlign())
,vTextAlign(params.vTextAlign())
,buttonPlacement(参数buttonPlacement())
{}
};
结构复选框:AbstractButton
{
布尔·伊萨托;
布尔值为3状态;
//定义基类“选项”类的扩展。
CPPX_定义_选项类(选项,抽象按钮::选项,
(伊萨托,布尔,真)
(is3State、bool、false)
)
显式复选框(Options const¶ms=Options())
:AbstractButton(参数)
,isAuto(params.isAuto())
,is3State(params.is3State())
{}
};
无效显示(复选框const&cb)
{
标准::cout
通过模板元编程和少量预处理,可以实现接近理想的语法:
//one has to "declare" once an attribute name to be able to use
//it later in any number of class declarations
DECLARE_ATTRIBUTE_NAME(foo);
DECLARE_ATTRIBUTE_NAME(quux);
DECLARE_ATTRIBUTE_NAME(bar);
DECLARE_ATTRIBUTE_NAME(baz);
//pass types and declared attribute names, separated by comma
typedef TupleWithNamedMembers<int, foo,
float, quux,
double, bar,
char, baz
> MyTuple;
//extra call to macro "MAKE_TUPLE" can be avoided, see below
class MyConstruct: public MAKE_TUPLE(MyTuple)
{ };
//usage
int main(int argc, char* argv[])
{
MyConstruct construct;
construct.foo = 3;
construct.bar = 5.6;
construct.quux = 8.9;
construct.baz = 'h';
return 0;
}
//一个属性名必须“声明”一次才能使用
//它稍后会出现在任意数量的类声明中
声明属性名称(foo);
声明属性名称(quux);
声明属性名称(条形);
声明属性名称(baz);
//传递类型和声明的属性名称,用逗号分隔
typedef TupleWithNamedMembers MyTuple;
//可以避免对宏“MAKE_TUPLE”的额外调用,如下所示
类MyConstruct:public MAKE_TUPLE(MyTuple)
{ };
//用法
int main(int argc,char*argv[])
{
MyConstruct结构;
construct.foo=3;
构造杆=5.6;
construct.qux=8.9;
construct.baz='h';
返回0;
}
实施:
#ifndef TupleWithNamedMembersH
#define TupleWithNamedMembersH
//---------------------------------------------------------------------------
#include <Loki/typelist.h>
#include <Loki/HierarchyGenerators.h>
template<class T, int a>
struct attribute
{
};
//the generated id is not really unique in all cases
//one should provide better implementation
#define GENERATE_UNIQ_ID(name) ((sizeof(#name)<<16)|__LINE__)
//specializations of the struct "attribute" act like compile-time map between
//a name ID and an attribute name
#define DECLARE_ATTRIBUTE_NAME_IMPL(name, id) \
enum { id = GENERATE_UNIQ_ID(name) }; \
template<class T> \
struct attribute<T,id> \
{\
T name;\
};
#define DECLARE_ATTRIBUTE_NAME(name)\
DECLARE_ATTRIBUTE_NAME_IMPL(name, name)
//helps to pass pair of type and name ID as a single type
template<class T, int i>
struct pair
{
static const int val = i;
typedef T type;
};
//unpacks compile-time data from PairT and inherits attribute
//with name selected by ID
template<class PairT>
class holder: public attribute<typename PairT::type,PairT::val>
{ };
//turns template arguments into Loki::TypeList
template
<
typename T1 = Loki::NullType, int i1 = 0, typename T2 = Loki::NullType, int i2 = 0,
typename T3 = Loki::NullType, int i3 = 0, typename T4 = Loki::NullType, int i4 = 0,
typename T5 = Loki::NullType, int i5 = 0, typename T6 = Loki::NullType, int i6 = 0,
typename T7 = Loki::NullType, int i7 = 0, typename T8 = Loki::NullType, int i8 = 0,
typename T9 = Loki::NullType, int i9 = 0, typename T10 = Loki::NullType, int i10 = 0
>
struct TupleWithNamedMembers
{
public:
typedef Loki::TL::MakeTypelist<pair<T1,i1>, pair<T2,i2>,
pair<T3,i3>, pair<T4,i4>,
pair<T5,i5>, pair<T6,i6>,
pair<T7,i7>, pair<T8,i8>,
pair<T9,i9>, pair<T10,i10>
>::Result Result;
};
//this macro is required because of internal compiler error that I encounter
//Loki::GenScatterHierarchy makes a class inherit every attribute from the type list
#define MAKE_TUPLE(types) Loki::GenScatterHierarchy<types::Result, holder>
#endif //end of "TupleWithNamedMembers.h"
\ifndef TupleWithNamedMembersH
#定义TupleWithNamedMembersH
//---------------------------------------------------------------------------
#包括
#包括
模板
结构属性
{
};
//产生
#ifndef TupleWithNamedMembersH
#define TupleWithNamedMembersH
//---------------------------------------------------------------------------
#include <Loki/typelist.h>
#include <Loki/HierarchyGenerators.h>
template<class T, int a>
struct attribute
{
};
//the generated id is not really unique in all cases
//one should provide better implementation
#define GENERATE_UNIQ_ID(name) ((sizeof(#name)<<16)|__LINE__)
//specializations of the struct "attribute" act like compile-time map between
//a name ID and an attribute name
#define DECLARE_ATTRIBUTE_NAME_IMPL(name, id) \
enum { id = GENERATE_UNIQ_ID(name) }; \
template<class T> \
struct attribute<T,id> \
{\
T name;\
};
#define DECLARE_ATTRIBUTE_NAME(name)\
DECLARE_ATTRIBUTE_NAME_IMPL(name, name)
//helps to pass pair of type and name ID as a single type
template<class T, int i>
struct pair
{
static const int val = i;
typedef T type;
};
//unpacks compile-time data from PairT and inherits attribute
//with name selected by ID
template<class PairT>
class holder: public attribute<typename PairT::type,PairT::val>
{ };
//turns template arguments into Loki::TypeList
template
<
typename T1 = Loki::NullType, int i1 = 0, typename T2 = Loki::NullType, int i2 = 0,
typename T3 = Loki::NullType, int i3 = 0, typename T4 = Loki::NullType, int i4 = 0,
typename T5 = Loki::NullType, int i5 = 0, typename T6 = Loki::NullType, int i6 = 0,
typename T7 = Loki::NullType, int i7 = 0, typename T8 = Loki::NullType, int i8 = 0,
typename T9 = Loki::NullType, int i9 = 0, typename T10 = Loki::NullType, int i10 = 0
>
struct TupleWithNamedMembers
{
public:
typedef Loki::TL::MakeTypelist<pair<T1,i1>, pair<T2,i2>,
pair<T3,i3>, pair<T4,i4>,
pair<T5,i5>, pair<T6,i6>,
pair<T7,i7>, pair<T8,i8>,
pair<T9,i9>, pair<T10,i10>
>::Result Result;
};
//this macro is required because of internal compiler error that I encounter
//Loki::GenScatterHierarchy makes a class inherit every attribute from the type list
#define MAKE_TUPLE(types) Loki::GenScatterHierarchy<types::Result, holder>
#endif //end of "TupleWithNamedMembers.h"
template
<
typename T1 = Loki::NullType, int i1 = 0, typename T2 = Loki::NullType, int i2 = 0,
typename T3 = Loki::NullType, int i3 = 0, typename T4 = Loki::NullType, int i4 = 0,
typename T5 = Loki::NullType, int i5 = 0, typename T6 = Loki::NullType, int i6 = 0,
typename T7 = Loki::NullType, int i7 = 0, typename T8 = Loki::NullType, int i8 = 0,
typename T9 = Loki::NullType, int i9 = 0, typename T10 = Loki::NullType, int i10 = 0
>
struct MakeTupleWithNamedMembers
{
private:
typedef Loki::TL::MakeTypelist<pair<T1,i1>, pair<T2,i2>,
pair<T3,i3>, pair<T4,i4>,
pair<T5,i5>, pair<T6,i6>,
pair<T7,i7>, pair<T8,i8>,
pair<T9,i9>, pair<T10,i10>
>::Result type_list;
public:
typedef Loki::GenScatterHierarchy<type_list, holder> Result;
};
//usage
class MyConstruct: public MakeTupleWithNamedMembers<int, foo, float, quux>::Result
{ };