Hallo, ich lerne C++ 11, ich frage mich, wie man ein constexpr 0 bis n Array erstellt, zum Beispiel:
n = 5;
int array[] = {0 ... n};
so kann Array sein {0, 1, 2, 3, 4, 5}
Christoph Aldama
Hallo, ich lerne C++ 11, ich frage mich, wie man ein constexpr 0 bis n Array erstellt, zum Beispiel:
n = 5;
int array[] = {0 ... n};
so kann Array sein {0, 1, 2, 3, 4, 5}
In C++14 geht das ganz einfach mit a constexpr
Konstruktor und eine Schleife:
#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';
}
das ist knapp. Warum ist : arr()
notwendig?
– Eisfeuer
24. Mai 2016 um 12:12 Uhr
@IceFire wahrscheinlich, weil Sie keine nicht initialisierten Felder enthalten können constexpr
Funktion (die hier ein Konstruktor ist). Nur eine Vermutung.
– Abyss
24. Mai 2016 um 12:57 Uhr
Wie könnten Sie eine Funktion an A übergeben, die auf alle Array-Elemente angewendet würde? Beim Benutzen template <int N, class Function> ... constexpr A(Function f) : arr() {...
Ich kann nicht herausfinden, wie man die Struktur instanziiert.
– Romeo Valentin
24. September 2019 um 16:11 Uhr
Hinweis: funktioniert nicht mit Visual Studio 15, wird möglicherweise in Visual Studio 2017 unterstützt.
– jjcf89
21. Februar 2020 um 15:37 Uhr
Ich bekomme das nicht zum Kompilieren. Ich verwende auch Visual Studio 15. Kann jemand bestätigen, dass es ab 2017 gültig ist?
– Markus K.
5. Mai 2020 um 15:21 Uhr
Kal
Im Gegensatz zu den Antworten in den Kommentaren zu Ihrer Frage können Sie dies ohne Compilererweiterungen tun.
#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
}
@Kal schön, aber “nur” funktioniert für int
oder andere Typen, die als Nicht-Typ-Template-Parameter erscheinen können (also nicht für z double
). Siehe meine Antwort für die allgemeine Lösung.
– TemplateRex
26. September 2013 um 8:49 Uhr
Hübsch. Aber ich denke, ich würde das rekursive variadische Template hinter einer nicht-variadischen öffentlichen Schnittstelle verstecken, um Verwirrung zu vermeiden, falls jemand es versucht Array<9,3,5>
.
– Aschepler
27. September 2013 um 16:50 Uhr
TemplateRex
Basierend auf der hervorragenden Idee von @Xeo ist hier ein Ansatz, mit dem Sie eine Reihe von füllen können
constexpr std::array<T, N> a = { fun(0), fun(1), ..., fun(N-1) };
T
ist ein beliebiger Literaltyp (nicht nur int
oder andere gültige Nichttyp-Vorlagenparametertypen), sondern auch double
oder std::complex
(ab C++14)fun()
ist beliebig constexpr
Funktionstd::make_integer_sequence
ab C++14, aber heute einfach mit g++ und Clang zu implementieren (siehe Live-Beispiel am Ende der Antwort)Hier ist der Code
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, ", "));
}
where auto is any literal type
Ist es nicht ein std::array
von wörtlichen Typen, in auto a = make_array<N>(fun);
gleichwertig auto a = std::array<decltype(fun(0)), N>{fun(0), fun(1), ..};
? Auch das Beispiel constexpr auto a = {1,2};
leitet ab a
ein … zu sein std::initializer_list
der noch kein Literaltyp sein muss (-> nein constexpr
). (Ich weiß, es ist ziemlich pedantisch, aber ich war auf den ersten Blick verwirrt.)
– dyp
27. September 2013 um 16:52 Uhr
Khurshid Normuradov
Verwenden Sie C++14 integral_sequence oder seine invariante 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: Sie können std::array verwenden:
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;
}
#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];
}
Leidenschaftlicher Programmierer
Mit dem Boost-Präprozessor ist es sehr einfach:
#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;
}
AUSGANG:
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
Erwägen boost::mpl::range_c<int, 0, N>
stattdessen.
Hier ist eine aktuelle ähnliche Frage mit
std::array
S.– dyp
26. September 2013 um 9:45 Uhr
Wir sind jetzt bei C++17. Die Antwort von @abyx ist jetzt also die beste Antwort, da sie nicht mehr als abhängig von “Compiler-Erweiterungen” angesehen werden kann.
– Spencer
22. April 2019 um 17:04 Uhr