2015-06-21 147 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