2015-06-21 144 views
2

要测试一些多维结构,需要生成编译时多维索引以完全覆盖所有可能的情况。在编译时完全枚举D维数组的索引

我搜索编译时便宜的方式来达到上述目的。

我做什么目前:

#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; 
} 

对于10 产生的情况下,它消耗大约十秒钟的处理器时间。如何改进解决方案,还是有更好的方法来达到目标​​?

+0

您的例子并不与[GCC(编译HTTP:// melpon。组织/ wandbox/permlink/ni6uS96vj686q5ls);除此之外,什么需要10秒?编译时间还是运行时间? –

+0

@ m.s。编译时间。我的编译器是* clang 3.6 *。 http://coliru.stacked-crooked.com/a/b7a53627ff17c1ec – Orient

回答

4

至于运行时,我会线性指标,做一个to_multi_index,是这样的:

// Is0 * Is1 * ... * Isn 
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

+0

不错,但我的眼睛=)。元编程在C++中是一种痛苦。这是更好的,那么我的解决方案,因为它提供了一个index_sequences的元组。它更适合我的应用程序。 – Orient

+0

看起来不错,但如果我想通过可变模板函数使用此代码,它不起作用。你知道为什么这会失败: 'template void test(){ \t all_indexes :: type {};}' – dgrat

+1

@dgrat:缺少'typename':'template void test(){typename all_indexes :: type {};/** /}'。 – Jarod42