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

met*_*tal 6 c++ crtp template-meta-programming c++14 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'; } );
}
Run Code Online (Sandbox Code Playgroud)

我想避免显式的类型列表 - D1,D2D3- 在创建中list因为这意味着我必须手动维护该列表,因为我似乎应该能够在类声明中或周围告诉编译器,"将此类添加到运行列表中".(我的最终目标是自动化工厂注册,这是缺失的机制.)

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

Pau*_* II 5

要在编译时完成此操作,需要“有状态”元编程。在这篇文章中 Filip Ros\xc3\xa9en 解释了如何使用极其先进的 C++14 实现以下内容:

\n\n
LX::push<void, void, void, void> ();\nLX::set<0, class Hello> ();\nLX::set<2, class World> ();\nLX::pop ();\n\nLX::value<> x; // type_list<class Hello, void, class World>\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n

或者,您可以重新构建代码以支持运行时注册,这要简单得多,并且可以跨编译器(例如 MSVC)移植。这就是Proveargs等库所使用的。它使用一个泛型auto_register类:

\n\n
template<class T, class F>\nint auto_register_factory()\n{\n    F::template apply<T>();\n    return 0;\n}\n\ntemplate<class T, class F>\nstruct auto_register\n{\n    static int static_register_;\n    // This typedef ensures that the static member will be instantiated if\n    // the class itself is instantiated\n    typedef std::integral_constant<decltype(&static_register_), &static_register_> static_register_type_;\n};\n\ntemplate<class T, class F>\nint auto_register<T, F>::static_register_ = auto_register_factory<T, F>();\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
struct foo_register\n{\n    template<class T>\n    static void apply()\n    {\n        // Do code when it encounters `T`\n    }\n};\n\ntemplate<class Derived>\nstruct fooable : auto_register<Derived, foo_register>\n{};\n
Run Code Online (Sandbox Code Playgroud)\n

  • @metal所以我发现通过将其放入模板参数中,编译器将始终实例化静态变量。我已经更新了代码。 (3认同)