c++ - 基于可变参数模板的类成员变量

标签 c++ templates c++14 template-meta-programming c++17

给定类型、名称和默认值列表,我可以轻松编写一个工具来生成有效的 C++ 代码,该代码声明一个类,其中包含每种类型、名称和默认值的成员变量。例如,给定列表

  • 整数,富,42
  • float ,酒吧,0.1f

(和类名“Baz”),它将生成

class Baz {
    int foo = 42;
    float bar = 0.1f;
}

如果一个工具可以生成这样一个类,难道编译器不能为我做吗?我正在考虑这些方面的事情(注意:这是伪代码):

template <typename ...MemberTypes> class Baz {
    MemberTypes::type... MemberTypes::name... = MemberTypes::default...;
}

上面的类会被创建成类似的东西

using MyBaz = Baz<member_type<int, "foo", 42>, member_type<float, "bar", 0.1f>>;

这可能的原因:

不可能的原因:

如果可行,如何实现?如果不可能,为什么不呢?即将到来的 c++17 在这方面有什么改变吗?

更新:示例问题: 通常,配置数据存储为字符串层次结构或某种其他形式的“任何类型”。然而,这会导致难看的代码 ( config.get<int>("core.timeout") ) 并阻止编译器帮助解决例如拼写错误 ( config.get<int>("core.timeuot") )。

通过用真实类型声明每个配置变量,编译器可以检查类型并防止拼写错误。但是,需要自定义代码将配置数据读取到正确的成员变量中。如果添加了新的配置开关,很容易忘记更新这段代码。

只指定所有成员的类型和名称,然后让编译器自动生成类(包括读取配置文件的方法)会很方便。这是我要求的功能的一个可能用例。

最佳答案

C++ 还没有反射工具。特别是,不可能按照您希望的方式生成和操作实体的名称。

然而,预处理器可以以有限的方式做到这一点,这(在 Boost.PP 的帮助下使其成为样板)使我们能够编写以下内容(直接取自 another answer of mine ):

#define GLK_PP_DETAIL_SEQ_DOUBLE_PARENS_0(...) \
     ((__VA_ARGS__)) GLK_PP_DETAIL_SEQ_DOUBLE_PARENS_1

#define GLK_PP_DETAIL_SEQ_DOUBLE_PARENS_1(...) \
     ((__VA_ARGS__)) GLK_PP_DETAIL_SEQ_DOUBLE_PARENS_0

#define GLK_PP_DETAIL_SEQ_DOUBLE_PARENS_0_END
#define GLK_PP_DETAIL_SEQ_DOUBLE_PARENS_1_END

// Double the parentheses of a Boost.PP sequence
// I.e. (a, b)(c, d) becomes ((a, b))((c, d))
#define GLK_PP_SEQ_DOUBLE_PARENS(seq) \
    BOOST_PP_CAT(GLK_PP_DETAIL_SEQ_DOUBLE_PARENS_0 seq, _END)


#define MAKE_ONE_VARIABLE(r, data, elem) \
    BOOST_PP_TUPLE_ELEM(0, elem) BOOST_PP_TUPLE_ELEM(1, elem) = BOOST_PP_TUPLE_ELEM(2, elem);

#define MAKE_CLASS(className, members) \
    struct className { \
        BOOST_PP_SEQ_FOR_EACH(MAKE_ONE_VARIABLE, ~, GLK_PP_SEQ_DOUBLE_PARENS(members)) \
    }

...并这样使用它:

MAKE_CLASS(Baz, (int, foo, 42)(float, bar, 0.1f));

...扩展为:

struct Baz {
    int foo = 42;
    float bar = 0.1f;
};

关于c++ - 基于可变参数模板的类成员变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44050323/

相关文章:

c++ - Lambda 闭包无法转换为 std::function

c++ - 是否可以在派生类中选择性地定义类型

c++ - 找出哪些函数被内联

c++ - 在不使用未命名命名空间的情况下在 header 中隐藏 C++ 类

c++ - 为什么不同的 GCC 4.9.2 安装会为这个正则表达式匹配提供不同的结果?

c++ - 编译时检查模板类型 C++

c++ - 函数模板特化类型——它是可选的吗?

c++ - typedef 类型名和从属范围

c++ - 如何设计符合标准的 std::any 实现的存储?

c++ - 在父容器中调用基于子容器的重载函数