c++ - 在编译时完全枚举 D 维数组的索引

标签 c++ c++11 c++14 constexpr

为了测试一些多维结构,需要生成编译时多维索引以完全覆盖所有可能的情况。

我寻找编译时廉价的方法来实现上述目的。

我目前在做什么:

#include <type_traits>
#include <utility>

template< typename F, std::size_t ...indices >
struct enumerator;

template< typename F >
struct enumerator< F >
{

    constexpr
    enumerator(F && _f)
        : f(std::forward< F >(_f))
    { ; }

    template< std::size_t ...I >
    constexpr
    bool
    operator () () const
    {
        return f(std::index_sequence< I... >{});
    }

private :

    F f;

};

template< typename F, std::size_t first, std::size_t ...rest >
struct enumerator< F, first, rest... >
    : enumerator< F, rest... >
{

    constexpr
    enumerator(F && _f)
        : enumerator< F, rest... >(std::forward< F >(_f))
    { ; }

    template< std::size_t ...I >
    constexpr
    bool
    operator () () const
    {
        return enumerator::template operator () < I... >(std::make_index_sequence< first >{}); // ltr
    }

    template< std::size_t ...I, std::size_t ...J >
    constexpr
    bool
    operator () (std::index_sequence< J... >) const
    {
        return (enumerator< F, rest... >::template operator () < I..., J >() && ...); // rtl, `< J, I... >` - ltr
    }

};

template< std::size_t ...I, typename F >
constexpr
enumerator< F, I... >
make_enumerator(F && f)
{
    static_assert(0 < sizeof...(I));
    static_assert(((0 < I) && ...));
    return std::forward< F >(f);
}

// main.cpp

#include <iostream>

#include <cstdlib>
#include <cassert>

struct truth
{

    template< std::size_t ...I >
    constexpr
    bool
    operator () (std::index_sequence< I... >) const
    {
        return true;
    }

};

struct printer
{

    template< std::size_t ...I >
    bool
    operator () (std::index_sequence< I... >) const
    {
        for (std::size_t const & i : {I...}) {
            std::cout << i << ' ';
        }
        std::cout << std::endl;
        return true;
    }

};

int
main()
{  
    static_assert(make_enumerator< 10, 10, 10, 10 >(truth{})());
    assert((make_enumerator< 3, 3, 3 >(printer{})()));
    return EXIT_SUCCESS;
}

对于 104 生成的案例,它会消耗大约 10 秒的处理器时间。如何改进解决方案,或者有更好的方法来实现目标?

最佳答案

至于运行时,我将线性索引并执行to_multi_index,例如:

// Is0 * Is1 * ... * Isn, So in C++17 (Is * ... * 1u)
template <std::size_t ... Is>
struct accum_mul;

template <>
struct accum_mul<> : std::integral_constant<std::size_t, 1u>{};

template <std::size_t I, std::size_t ... Is>
struct accum_mul<I, Is...> :
    std::integral_constant<std::size_t, I * accum_mul<Is...>::value>{};

template <typename Seq, typename Res = std::tuple<>>
struct coeff;

template <typename Res>
struct coeff<std::index_sequence<>, Res> {
  using type = Res;
};

template <std::size_t I, std::size_t ... Is, typename ... TRes>
struct coeff<std::index_sequence<I, Is...>,
             std::tuple<TRes...>>
    : coeff<std::index_sequence<Is...>,
            std::tuple<TRes..., accum_mul<Is...>>> {};

template <std::size_t I, typename coeffs, typename dims, typename Seq>
struct to_multi_index;

template <std::size_t I, typename coeffs, typename dims, std::size_t... Is>
struct to_multi_index<I, coeffs, dims, std::index_sequence<Is...>>
{
    using type = std::index_sequence<(I / (std::tuple_element<Is, coeffs>::type::value)
    % (std::tuple_element<Is, dims>::type::value))...>;
};

template <typename Indexes, typename coeffs, typename dims, typename dim_indexes>
struct to_multi_indexes;

template <std::size_t... Is, typename coeffs, typename dims, typename dim_indexes>
struct to_multi_indexes<std::index_sequence<Is...>, coeffs, dims, dim_indexes>
{
    using type = std::tuple<typename to_multi_index<Is, coeffs, dims, dim_indexes>::type...>;
};

template <std::size_t...Is>
struct all_indexes
{
private:
    using as_seq = std::index_sequence<Is...>;
    using as_tuple = std::tuple<std::integral_constant<std::size_t, Is>...>;
    using dim_index = std::make_index_sequence<sizeof...(Is)>;
    using coeffs = typename coeff<as_seq>::type;
    using elem_count = accum_mul<Is...>;
    using index_seq = std::make_index_sequence<elem_count::value>;
public:
    using type = typename to_multi_indexes<index_seq, coeffs, as_tuple, dim_index>::type;
};

Live demo

关于c++ - 在编译时完全枚举 D 维数组的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30962470/

相关文章:

c++ - 如何将函数参数传递给 boost::thread_groups::create_thread()

c++ - QTableView拖放行无法正常工作

c++ - 在 C++ 中使用函数指针映射枚举键和值

c++ - jsoncpp:将字符串转换为 double

c++ - 检查变量是否属于具有特定基类的类

c++ - 配置软件时出错

c++ - 数据访问对象模式实现

c++ - 编译时检查 trait specialization 是否有唯一的 id

c++ - 从与 `this` 相同的模板创建实例?

c++ - 标准中的哪个地方说成员别名声明可以像静态成员一样使用?