首页 > 解决方案 > 创建重复声明

问题描述

我想知道是否有人知道创建重复类型声明的方法,因为这可能会令人困惑,所以一个示例会有所帮助:

对于我们的项目,我们需要有函数和类型声明,例如:

    using FunType = std::function<void(double,double,double,double,double,double,double,double)>;
    using DataType = std::tuple<double,double,double,double,double,double,double,double>;

分散在多个文件中,多次,最多 32 个双打(如果这很重要,只有双打)。

我很乐意用以下虚构代码行中的内容替换这些双打的手动写入/计数:

    using FunType = something_generate_function_decl<8>;
    using DataType = something_generate_datatype_decl<8>

如果可能的话,我想远离 boost 及其预处理器库。

编辑以提供一些说明

大图是,在应用程序的某个时刻,我们得到一系列字节(表示一个双精度数组),每个值都具有预定义的含义,我们需要对它们进行验证(每个值都需要用几个条件进行验证为了有效性),拒绝无效数据,记录相应的无效数据及其含义,将有意义的数据传递给应用程序,从记录器模块到十几个不同的地方,包括现有函数以及已经定义语法的 Qt 信号等。 .. 在某些时候这会从我们手中消失,所以这就是为什么我想创建尽可能容易阅读和可验证的代码。

Edit2提供更多说明

阅读评论,似乎对这个问题的范围有很多困惑。问题中故意遗漏了很多信息,这些信息与问题的纯粹本质无关,即如何将这 8 个(或 9 个、12 个或 32 个双打)缩短为更易于管理的实体。丢失的信息是我们处理接收到的数据的内部方式(我们有一个大规模的项目,因此您可以想象数据有几层抽象,可以进行自动验证、转换等......在发送之前,所以不是整个应用程序都是一长串 if/else 语句和带参数的基本函数调用),整个事情的唯一限制是,作为一个简单的双精度数组(代表一条消息)进来的东西经过验证,然后发送到已经具有预定义接口的函数/QT 信号/C++11 lambdas。所有的信息处理和验证都封装在类层中,这些类只是在某处注册自己(超出本问题的范围),用于接收、存储、验证和发送数据,例如,FunType(实际上是消息类的内部使用类型)表示函数/插槽/lambdas的接口,特定消息(及其已验证成员)将通过某种将所有成员收集到元组中的机制自动发送到该接口(DataType) 以及使用可变参数模板的一些index_sequence魔法,编译器将元组匹配到所需的函数,该函数在某个时间点“订阅”了这个消息。@admin 如果您觉得此编辑不相关,请随时将其删除。

标签: c++templates

解决方案


这很容易使用Boost.Mp11

#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>

namespace mp11 = boost::mp11;

template<class... Args>
using make_fn = std::function<void(Args...)>;

using TypeList = mp11::mp_repeat_c<mp11::mp_list<double>, 8>;
using FunType  = mp11::mp_apply<make_fn,    TypeList>;
using DataType = mp11::mp_apply<std::tuple, TypeList>;

没有 Boost 的替代 C++14 解决方案:

template<template<class...> class Fn, class T, std::size_t n>
struct apply_repeat {
    template<std::size_t... is>
    static Fn<decltype(is, T{})...> 
        get_type(std::index_sequence<is...>);

    using type = decltype(get_type(std::make_index_sequence<n>{}));
};

template<class... Args>
using make_fn = std::function<void(Args...)>;

using FunType  = typename apply_repeat<make_fn,    double, 8>::type;
using DataType = typename apply_repeat<std::tuple, double, 8>::type;

此解决方案需要一个默认的可构造的T. 满足这一要求double

为了解除这个要求,我们可以使用type_identity包装器(将成为 C++20 的一部分):

template<class T> 
struct type_identity {
    using type = T;
};

template<template<class...> class Fn, class T, std::size_t n>
struct apply_repeat {
    template<std::size_t... is>
    static Fn<typename decltype(is, type_identity<T>{})::type...> 
        get_type(std::index_sequence<is...>);

    using type = decltype(get_type(std::make_index_sequence<n>{}));
};

推荐阅读