2013-09-26 48 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