【问题标题】:How to efficiently roll out a sequence using c++ templates如何使用 C++ 模板有效地推出序列
【发布时间】:2018-07-08 00:28:31
【问题描述】:

我有一个复杂类型C,这取决于我在(长度有界)序列中需要的模板参数。 constexpr 函数next() 可用于从 C_n -> C_n+1。由于每个序列元素都有不同的类型,我使用std::tuple 来存储结果。 mkTuple() 函数负责(有限的)序列推出。

这是我所做的一个简化示例(使用std::array 作为我更复杂的 C 的占位符):

#include <array>
#include <tuple>
#include <iostream>


template<std::size_t OFFSET>
using C=std::array<uint8_t, OFFSET>;

static
constexpr
std::size_t
next(const std::size_t START, const std::size_t DISTANCE)
{
    return START + DISTANCE;
}


template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE, std::size_t SEQ_LENGTH>
struct mkTuple
{
    using _LT = CONTENT<START>;
    using _RT = typename mkTuple<CONTENT, next(START, DISTANCE), DISTANCE, SEQ_LENGTH - 1>::tuple;
    using tuple=decltype(std::tuple_cat(std::make_tuple(_LT()), _RT()));
};


template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE>
struct mkTuple<CONTENT, START, DISTANCE, 1>
{
    using _LT = CONTENT<START>;
    using tuple = std::tuple<_LT>;
};


int
main()
{
    using tMyTuple = typename mkTuple<C, 16, 2, 64>::tuple;

    const std::size_t iTupleLength = std::tuple_size<tMyTuple>::value;
    std::cout << "Sequence length =  " << iTupleLength << std::endl;

    const tMyTuple myTuple;
    std::cout << "Tuple[4].size() =  " << std::get<4>(myTuple).size() << std::endl;

    return 0;
}

问题是我的mkTuple() 函数似乎内存太贵,以至于我很快遇到了编译器内存不足的问题。事实上g++ -ftime-report ... 报告模板实例化的使用量 >1GB。而且这个数字会随着序列长度的增加而迅速(呈指数增长?)。

我怀疑std::tuple_cat 所需的std::tuple 实例化是充气机。有人知道如何更有效地推出序列吗?

提前谢谢!

【问题讨论】:

    标签: c++ c++11 templates stdtuple


    【解决方案1】:

    似乎std::tuple 对您的场景来说是多余的 - 您只能在类型系统级别上工作,然后在最后转换为 std::tuple

    由于std::tuple的实现又大又复杂,所以对于大量实例化会很慢也就不足为奇了。滚动你自己的typelist

    template <typename... Ts>
    struct typelist 
    { 
        using as_tuple = std::tuple<Ts...>; 
    };
    
    template <typename... As, typename... Bs>
    constexpr auto typelist_cat(typelist<As...>, typelist<Bs...>) 
        -> typelist<As..., Bs...> 
    {
        return {};
    }
    

    然后替换std::tuple的用法:

    template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE, std::size_t SEQ_LENGTH>
    struct mkTuple
    {
        using _LT = CONTENT<START>;
        using _RT = typename mkTuple<CONTENT, START + DISTANCE, DISTANCE, SEQ_LENGTH - 1>::tuple;
        using tuple = decltype(typelist_cat(typelist<_LT>{}, _RT{}));
    };
    
    
    template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE>
    struct mkTuple<CONTENT, START, DISTANCE, 1>
    {
        using _LT = CONTENT<START>;
        using tuple = typelist<_LT>;
    };
    

    最后,在最后进行转换:

    using tMyTuple = typename mkTuple<C, 16, 2, 64>::tuple::as_tuple;
    

    live wandbox example

    输出:

    序列长度 = 64

    元组[4].size() = 24

    【讨论】:

    • 哇...好简单!我没有想到我自己的类型列表。这是一个令人印象深刻的紧凑和正确的答案。非常感谢。
    猜你喜欢
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 2021-07-12
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多