2013-09-26 86 views
40

你好我正在學習C++ 11,我想知道如何使一個constexpr 0到n陣列,例如:創建N元件陣列constexpr C++ 11

n = 5; 

int array[] = {0 ... n}; 

所以陣列可能是{0, 1, 2, 3, 4, 5}

+2

[這是最近類似的問題](http://stackoverflow.com/q/19016099/420683)使用'std :: array's。 – dyp

回答

41

不像那些在你的問題的評論中的答案,你可以做到這一點,沒有編譯器擴展。

#include <iostream> 

template<int N, int... Rest> 
struct Array_impl { 
    static constexpr auto& value = Array_impl<N - 1, N, Rest...>::value; 
}; 

template<int... Rest> 
struct Array_impl<0, Rest...> { 
    static constexpr int value[] = { 0, Rest... }; 
}; 

template<int... Rest> 
constexpr int Array_impl<0, Rest...>::value[]; 

template<int N> 
struct Array { 
    static_assert(N >= 0, "N must be at least 0"); 

    static constexpr auto& value = Array_impl<N>::value; 

    Array() = delete; 
    Array(const Array&) = delete; 
    Array(Array&&) = delete; 
}; 

int main() { 
    std::cout << Array<4>::value[3]; // prints 3 
} 
+0

@Kal很好,但「only」適用於'int'或其他類型,可以顯示爲非類型模板參數(因此不適用於例如'double')。查看我的答案以獲得一般解決方案。 – TemplateRex

+0

不錯。但是我想我會隱藏非可變公共接口後面的遞歸可變參數模板,以避免有人嘗試'Array <9,3,5>'時發生混淆。 – aschepler

4

使用C++ 14 integral_sequence,或其不變index_sequence

#include <iostream> 

template< int ... I > struct index_sequence{ 

    using type = index_sequence; 
    using value_type = int; 

    static constexpr std::size_t size()noexcept{ return sizeof...(I); } 
}; 

// making index_sequence 
template< class I1, class I2> struct concat; 

template< int ...I, int ...J> 
struct concat< index_sequence<I...>, index_sequence<J...> > 
     : index_sequence< I ... , (J + sizeof...(I))... > {}; 

template< int N > struct make_index_sequence_impl; 

template< int N > 
using make_index_sequence = typename make_index_sequence_impl<N>::type; 

template< > struct make_index_sequence_impl<0> : index_sequence<>{}; 
template< > struct make_index_sequence_impl<1> : index_sequence<0>{}; 

template< int N > struct make_index_sequence_impl 
    : concat< make_index_sequence<N/2>, make_index_sequence<N - N/2> > {}; 



// now, we can build our structure. 
template < class IS > struct mystruct_base; 

template< int ... I > 
struct mystruct_base< index_sequence< I ... > > 
{ 

    static constexpr int array[]{I ... }; 
}; 

template< int ... I > 
constexpr int mystruct_base< index_sequence<I...> >::array[] ; 

template< int N > struct mystruct 
    : mystruct_base< make_index_sequence<N > > 
{}; 

int main() 
{ 
    mystruct<20> ms; 

    //print 
    for(auto e : ms.array) 
    { 
     std::cout << e << ' '; 
    } 
    std::cout << std::endl; 

    return 0; 
} 

output: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 

UPDATE: 您可以使用std ::數組:

template< int ... I > 
static constexpr std::array< int, sizeof...(I) > build_array(index_sequence<I...>) noexcept 
{ 
    return std::array<int, sizeof...(I) > { I... }; 
} 

int main() 
{ 
    std::array<int, 20> ma = build_array(make_index_sequence<20>{}); 

    for(auto e : ma) std::cout << e << ' '; 
    std::cout << std::endl; 
} 
+1

哪個編譯器支持這個? – TemplateRex

+0

Clang + libC++提示樹支持這個。通過'-std = C++ 1y'。 –

+0

我使用Clang 3.3和GCC 4.8。1與-std = C++ 11選項。 –

25

基於@ XEO的excellent idea,這裏有一種方法可以讓你填充一組數字

  • constexpr std::array<T, N> a = { fun(0), fun(1), ..., fun(N-1) };
  • 其中T是任何文本類型(不只是int或其他有效的非類型模板參數類型),也double,或std::complex(從C++ 14以後)
  • 其中fun()是任何constexpr功能
  • 其通過 std::make_integer_sequence從C++ 14向前今天支持,但很容易地實現與
  • 既g ++以及鏘(參見實施例直播在答案的末尾)
  • 我用@JonathanWakely的implementation at GitHub(升壓許可證)

下面是代碼

template<class Function, std::size_t... Indices> 
constexpr auto make_array_helper(Function f, std::index_sequence<Indices...>) 
-> std::array<typename std::result_of<Function(std::size_t)>::type, sizeof...(Indices)> 
{ 
    return {{ f(Indices)... }}; 
} 

template<int N, class Function> 
constexpr auto make_array(Function f) 
-> std::array<typename std::result_of<Function(std::size_t)>::type, N> 
{ 
    return make_array_helper(f, std::make_index_sequence<N>{});  
} 

constexpr double fun(double x) { return x * x; } 

int main() 
{ 
    constexpr auto N = 10; 
    constexpr auto a = make_array<N>(fun); 

    std::copy(std::begin(a), std::end(a), std::ostream_iterator<double>(std::cout, ", ")); 
} 
使用升壓預處理

Live Example

+0

'在哪裏汽車是任何文字類型'是不是'文字類型的'std :: array',在'auto a = make_array (fun);',相當於'auto a = std :: array {fun(0),fun(1),..};'?此外,示例'constexpr auto a = {1,2};'推導出'a'是一個'std :: initializer_list',它還不需要是一個文字類型( - > no'constexpr')。 (我知道這很迂腐,但我第一眼就很困惑。) – dyp

1
#include <array> 
#include <iostream> 

template<int... N> 
struct expand; 

template<int... N> 
struct expand<0, N...> 
{ 
    constexpr static std::array<int, sizeof...(N) + 1> values = {{ 0, N... }}; 
}; 

template<int L, int... N> struct expand<L, N...> : expand<L-1, L, N...> {}; 

template<int... N> 
constexpr std::array<int, sizeof...(N) + 1> expand<0, N...>::values; 

int main() 
{ 
    std::cout << expand<100>::values[9]; 
} 
1

,這是非常簡單的。

#include <cstdio> 
#include <cstddef> 

#include <boost/preprocessor/repeat.hpp> 
#include <boost/preprocessor/comma_if.hpp> 

#define IDENTITY(z,n,dummy) BOOST_PP_COMMA_IF(n) n 

#define INITIALIZER_n(n) { BOOST_PP_REPEAT(n,IDENTITY,~) } 

int main(int argc, char* argv[]) 
{ 
    int array[] = INITIALIZER_n(25); 

    for(std::size_t i = 0; i < sizeof(array)/sizeof(array[0]); ++i) 
     printf("%d ",array[i]); 

    return 0; 
} 

OUTPUT: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

+0

我想你也可以使用'ENUM'宏中的一個,例如'BOOST_PP_ENUM_PARAMS(25,BOOST_PP_EMPTY())',而不是'REPEAT' +'COMMA_IF' – dyp

14

在C++ 14它可以與constexpr構造函數和循環中容易實現:

#include <iostream> 

template<int N> 
struct A { 
    constexpr A() : arr() { 
     for (auto i = 0; i != N; ++i) 
      arr[i] = i; 
    } 
    int arr[N]; 
}; 

int main() { 
    constexpr auto a = A<4>(); 
    for (auto x : a.arr) 
     std::cout << x << '\n'; 
} 
+0

這是簡潔的。爲什麼需要':arr()'? – IceFire

+1

@IceFire可能是因爲你在'constexpr'函數中沒有未初始化的字段(這裏是一個構造函數)。只是一個猜測。 – Abyx

0

嘗試boost::mpl::range_c<int, 0, N>docs