C ++ 14元编程:在编译/初始化时自动构建类型列表

时间:2017-02-06 20:51:26

标签: c++ c++14 template-meta-programming crtp boost-hana

使用C ++ 14以及奇怪重复模板模式(CRTP)和可能Boost.Hana(或boost::mpl如果您愿意)的某种组合,我可以在编译时构建类型列表(或静态初始化时间)没有明确的声明?

举个例子,我有类似的东西(见 Coliru ):

#include <iostream>
#include <boost/hana/tuple.hpp>
#include <boost/hana/for_each.hpp>

namespace
{
    struct D1 { static constexpr auto val = 10; };
    struct D2 { static constexpr auto val = 20; };
    struct D3 { static constexpr auto val = 30; };
}

int main()
{
    // How to avoid explicitly defining this?
    const auto list = boost::hana::tuple< D1, D2, D3 >{}; 

    // Do something with list
    boost::hana::for_each( list, []( auto t ) { std::cout << t.val << '\n'; } );
}

我希望在创建D1时避免明确的类型列表 - D2D3list,因为这意味着我必须维护当我似乎能够在类声明中或周围告诉编译器“将此类添加到运行列表”时,手动列出该列表。 (我的最终目标是自动化工厂注册,这是缺失的机制。)

我可以使用一些继承和/或元编程技巧在编译时或静态初始化时编写列表吗?

3 个答案:

答案 0 :(得分:4)

听起来你想要在命名空间或其他范围内获得所有类型的编译时元组。要做到这一点,你需要静态反射,这还没有被添加到C ++中(但是你发现它会非常有用)。您可以阅读one proposal for static reflection hereN4428 proposal here

作为一种解决方法,您可以编写一个宏来同时定义类型,并在静态初始化期间将其隐式添加到注册表中。

答案 1 :(得分:4)

要在编译时执行此操作,需要“有状态”元编程。在本文here中,FilipRoséen解释了如何使用非常高级的C ++ 14实现以下功能:

LX::push<void, void, void, void> ();
LX::set<0, class Hello> ();
LX::set<2, class World> ();
LX::pop ();

LX::value<> x; // type_list<class Hello, void, class World>

此外,Matt Calabrese使用类似的技术在C ++ 11中实现基于语义的概念,请参阅第28页幻灯片中的videoslides

当然,这些技术依赖于支持符合要求的两阶段名称查找的编译器。

或者,您可以恢复代码以支持运行时注册,这样更简单,并且可以在MSVC等编译器之间移植。这就是Proveargs等库使用的内容。它使用通用的auto_register类:

template<class T, class F>
int auto_register_factory()
{
    F::template apply<T>();
    return 0;
}

template<class T, class F>
struct auto_register
{
    static int static_register_;
    // This typedef ensures that the static member will be instantiated if
    // the class itself is instantiated
    typedef std::integral_constant<decltype(&static_register_), &static_register_> static_register_type_;
};

template<class T, class F>
int auto_register<T, F>::static_register_ = auto_register_factory<T, F>();

然后你可以编写自己的CRTP类:

struct foo_register
{
    template<class T>
    static void apply()
    {
        // Do code when it encounters `T`
    }
};

template<class Derived>
struct fooable : auto_register<Derived, foo_register>
{};

答案 2 :(得分:1)

我现在知道这样做的唯一方法就是描述here所述的有状态元编程。但这很棘手,难以实施,委员会试图将其排除为无效。