6

使用 C++14 和 Curiously Recurring Template Pattern (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'; } );
}

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

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

4

3 回答 3

4

听起来您想在命名空间或其他范围内获取所有类型的编译时元组。为此,您需要静态反射,它尚未添加到 C++ 中(但正如您所发现的那样非常有用)。您可以在此处阅读关于静态反射的一项提案,并在此处阅读N4428 提案

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

于 2017-02-06T21:12:33.603 回答
4

在编译时执行此操作将需要“有状态”元编程。在这篇文章中 Filip Rosé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 中的视频幻灯片

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

或者,您可以重新构建代码以支持运行时注册,这更简单,并且可以跨编译器(如 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>
{};
于 2017-02-12T17:54:28.833 回答
1

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

于 2017-02-07T16:36:01.870 回答