I am using GCC8.2 and I would like to define a hierarchical tuple like this:
std::tuple<std::array<double,N>,
std::array<double,N/2>,
std::array<double,N/4>,
...,
std::array<double,2> > v ;
And then I have an algorithm to fill those arrays with the following specification:
template <int N>
std::array<double,N> get_array()
How can I write a generic algorithm to declare the tuple and fill it at compile time for any N?
Without recursion, you might do something like:
template <std::size_t N>
std::array<double, N> get_array() { return {{}}; }
namespace detail
{
constexpr std::size_t log2(std::size_t n)
{
std::size_t res = 0;
while (n != 0) {
n /= 2;
++res;
}
return res;
}
template <std::size_t N, std::size_t ...Is>
auto make_array_tuple_impl(std::index_sequence<Is...>)
{
return make_tuple(get_array<(N >> Is)>()...);
}
}
template <std::size_t N>
auto make_array_tuple()
{
return detail::make_array_tuple_impl<N>(std::make_index_sequence<detail::log2(N) - 1>());
}
Demo
This feels a bit involved, maybe there's a simpler solution.
// Pack of values
template <auto...>
struct vpack { };
// Concatenating two packs
template <class, class>
struct vpack_cat_;
template <auto... lhs, auto... rhs>
struct vpack_cat_<vpack<lhs...>, vpack<rhs...>> {
using type = vpack<lhs..., rhs...>;
};
template <class Lhs, class Rhs>
using vpack_cat = typename vpack_cat_<Lhs, Rhs>::type;
// Building a decreasing exp scale...
template <int N>
struct exp_scale_ {
using type = vpack_cat<
vpack<N>,
typename exp_scale_<N / 2>::type
>;
};
// ... stopping at 2
template <>
struct exp_scale_<2> {
using type = vpack<2>;
};
template <int N>
using exp_scale = typename exp_scale_<N>::type;
// Building the tuple's type from the scale
template <class ScalePack>
struct exp_tuple_;
template <auto... Scale>
struct exp_tuple_<vpack<Scale...>> {
using type = std::tuple<std::array<double, Scale>...>;
};
template <class Scale>
using exp_tuple = typename exp_tuple_<Scale>::type;
// The known get_array() function
template <int N>
std::array<double,N> get_array() { return {}; }
// Initializing the tuple
template <auto... Scale>
auto get_tuple(vpack<Scale...>) {
return exp_tuple<vpack<Scale...>>{
get_array<Scale>()...
};
}
template <int N>
auto get_tuple() {
return get_tuple(exp_scale<N>{});
}
See it live on Coliru
Are you sure that your sequence in
std::tuple<std::array<double,N>,
std::array<double,N/2>,
std::array<double,N/4>,
...,
std::array<double,2> > v ;
ends with 2?
Supposing that you want to end with 2 or 1, I suppose you can use the following custom type traits to get the wanted index sequence
template <std::size_t N, std::size_t ... Is>
struct divSequence : public divSequence<(N>>1u), Is..., (N>>1u)>
{ };
template <std::size_t ... Is>
struct divSequence<2u, Is...> : public std::index_sequence<Is...>
{ };
template <std::size_t ... Is>
struct divSequence<1u, Is...> : public std::index_sequence<Is...>
{ };
So you only need the following make function (with helper)
template <std::size_t ... Is>
std::tuple<std::array<double, Is>...>
getDivTupleHelper (std::index_sequence<Is...> const &)
{ return { get_array<Is>()... }; }
template <std::size_t N>
auto getDivTuple ()
{ return getDivTupleHelper(divSequence<N>{}); }
The following is a full compiling C++14 example
#include <array>
#include <tuple>
#include <utility>
template <std::size_t N>
std::array<double,N> get_array ()
{ return {{ }}; }
template <std::size_t N, std::size_t ... Is>
struct divSequence : public divSequence<(N>>1u), Is..., (N>>1u)>
{ };
template <std::size_t ... Is>
struct divSequence<2u, Is...> : public std::index_sequence<Is...>
{ };
template <std::size_t ... Is>
struct divSequence<1u, Is...> : public std::index_sequence<Is...>
{ };
template <std::size_t ... Is>
std::tuple<std::array<double, Is>...>
getDivTupleHelper (std::index_sequence<Is...> const &)
{ return { get_array<Is>()... }; }
template <std::size_t N>
auto getDivTuple ()
{ return getDivTupleHelper(divSequence<N>{}); }
int main ()
{
using t0 = decltype( getDivTuple<15u>() );
using t1 = std::tuple<std::array<double, 7u>,
std::array<double, 3u>,
std::array<double, 1u>>;
using t2 = decltype( getDivTuple<16u>() );
using t3 = std::tuple<std::array<double, 8u>,
std::array<double, 4u>,
std::array<double, 2u>>;
static_assert( std::is_same<t0, t1>::value, "!");
static_assert( std::is_same<t2, t3>::value, "!");
}
If you need a C++11 solution... well... instead of std::index_sequence you can use a custom trivial substitute as
template <std::size_t ...>
struct myIndexSequence
{ }
and you need rewrite getDivTuple() to explicit the return type using decltype(); something as
template <std::size_t N>
decltype(getDivTupleHelper(divSequence<N>{})) getDivTuple ()
{ return getDivTupleHelper(divSequence<N>{}); }
Related
How do I initialize std::array<T, n> if T is not default constructible?
I know it's possible to initialize it like that:
T t{args};
std::array<T, 5> a{t, t, t, t, t};
But n for me is template parameter:
template<typename T, int N>
void f(T value)
{
std::array<T, N> items = ???
}
And even if it wasn't template, it's quite ugly to repeat value by hand if n is too large.
Given N, you could generate a sequence-type calledseq<0,1,2,3,...N-1> using a generator called genseq_t<>, then do this:
template<typename T, int N>
void f(T value)
{
//genseq_t<N> is seq<0,1,...N-1>
std::array<T, N> items = repeat(value, genseq_t<N>{});
}
where repeat is defined as:
template<typename T, int...N>
auto repeat(T value, seq<N...>) -> std::array<T, sizeof...(N)>
{
//unpack N, repeating `value` sizeof...(N) times
//note that (X, value) evaluates to value
return {(N, value)...};
}
And the rest is defined as:
template<int ... N>
struct seq
{
using type = seq<N...>;
static const std::size_t size = sizeof ... (N);
template<int I>
struct push_back : seq<N..., I> {};
};
template<int N>
struct genseq : genseq<N-1>::type::template push_back<N-1> {};
template<>
struct genseq<0> : seq<> {};
template<int N>
using genseq_t = typename genseq<N>::type;
Online demo
Hope that helps.
Sadly the existing answers here don't work for non-copyable types. So I took #Nawaz answer and modified it:
#include <utility>
#include <array>
template<typename T, size_t...Ix, typename... Args>
std::array<T, sizeof...(Ix)> repeat(std::index_sequence<Ix...>, Args &&... args) {
return {{((void)Ix, T(args...))...}};
}
template<typename T, size_t N>
class initialized_array: public std::array<T, N> {
public:
template<typename... Args>
initialized_array(Args &&... args)
: std::array<T, N>(repeat<T>(std::make_index_sequence<N>(), std::forward<Args>(args)...)) {}
};
Note that this is an std::array subclass so that one can easily write
class A {
A(int, char) {}
}
...
class C {
initialized_array<A, 5> data;
...
C(): data(1, 'a') {}
}
Without repeating the type and size. Of course, this way can also be implemented as a function initialize_array.
Following will solve your issue:
#if 1 // Not in C++11, but in C++1y (with a non linear better version)
template <std::size_t ...> struct index_sequence {};
template <std::size_t I, std::size_t ...Is>
struct make_index_sequence : make_index_sequence<I - 1, I - 1, Is...> {};
template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
#endif
namespace detail
{
template <typename T, std::size_t ... Is>
constexpr std::array<T, sizeof...(Is)>
create_array(T value, index_sequence<Is...>)
{
// cast Is to void to remove the warning: unused value
return {{(static_cast<void>(Is), value)...}};
}
}
template <std::size_t N, typename T>
constexpr std::array<T, N> create_array(const T& value)
{
return detail::create_array(value, make_index_sequence<N>());
}
So test it:
struct NoDefaultConstructible {
constexpr NoDefaultConstructible(int i) : m_i(i) { }
int m_i;
};
int main()
{
constexpr auto ar1 = create_array<10>(NoDefaultConstructible(42));
constexpr std::array<NoDefaultConstructible, 10> ar2 = create_array<10>(NoDefaultConstructible(42));
return 0;
}
Inspired by #Nawaz, this is more concise and makes better use of the standard: https://godbolt.org/z/d6a7eq8T5
#include <array>
#include <type_traits>
#include <fmt/format.h>
#include <fmt/ranges.h>
// Inspired by https://stackoverflow.com/a/18497366/874660
//! Return a std::array<T, Sz> filled with
//! calls to fn(i) for i in the integer sequence:
template <typename Int, Int...N, typename Fn>
[[nodiscard]] constexpr auto transform_to_array(std::integer_sequence<Int, N...>, Fn fn) {
return std::array{(static_cast<void>(N), fn(N))...};
}
//! Repeated application of nullary fn:
template <std::size_t N, typename Fn>
[[nodiscard]] constexpr auto generate_n_to_array(Fn fn) -> std::array<decltype(fn()), N> {
return transform_to_array(std::make_integer_sequence<std::size_t, N>(), [&](std::size_t) { return fn(); });
}
int main() {
static constexpr std::array<int, 3> a = generate_n_to_array<3>([i = 0]() mutable { return 2 * (i++); });
fmt::print("{}\n", a);
}
There are already many great answers, so a single remark:
most of them use N twice: once in the array<T,N> and once in the repeat/genseq/generate/whatever you call it...
Since we are using a single value anyway, it seems we can avoid repeating the size twice, here's how:
#include <iostream>
#include <array>
#include <type_traits>
// Fill with a value -- won't work if apart from non-default-constructible, the type is also non-copyable...
template <typename T>
struct fill_with {
T fill;
constexpr fill_with(T value) : fill{value} {}
template <typename... Args>
constexpr fill_with(std::in_place_type_t<T>, Args&&... args) : fill{ T{std::forward<Args>(args)...} } {}
template <typename U, size_t N>
constexpr operator std::array<U, N> () {
return [&]<size_t... Is>(std::index_sequence<Is...>) {
return std::array{ ((void)Is, fill)... };
}(std::make_index_sequence<N>{});
}
};
// A little more generic, but requires C++17 deduction guides, otherwise using it with lambdas is a bit tedious
template <typename Generator>
struct construct_with {
Generator gen;
template <typename F> constexpr construct_with(F && f) : gen{std::forward<F>(f)} {}
template <typename U, size_t N>
constexpr operator std::array<U, N> () {
return [&]<size_t... Is>(std::index_sequence<Is...>) {
return std::array{ ((void)Is, gen())... };
}(std::make_index_sequence<N>{});
}
};
template <typename F>
construct_with(F&&) -> construct_with<F>;
struct A {
A(int){}
A(A const&) = delete;
};
int main() {
std::array<int, 7> arr = fill_with<int>{ 7 };
std::array<int, 7> arr = fill_with{ 7 }; // Ok since C++17
// or you can create a maker function to wrap it in pre-c++17 code, as usual.
std::array<A, 7> as = construct_with{[]{ return A{7}; }};
for (auto & elem : arr) std::cout << elem << '\n';
}
Note: Here I used a few C++20 constructs, which may or may not be an issue in your case, but changing from one to the other is pretty straight-forward
I'd also recommend using <type_traits> and std::index_sequence and all the other sequences from the std if possible to avoid reinventing the wheel)
I'm trying to determine how to take in a boolean template parameter pack
template<bool...B> struct BoolPack{};
and construct from it an integer parameter pack where the values indicate the enumeration of the true elements in BoolPack. The enumeration could be contained like this:
template<size_t...I> struct IntegerSequence{};
The function should take in a BoolPack<B...> and return an IntegerSequence<I...>;
template<bool...B>
constexpr auto enumerate( const BoolPack<B...>& b ) {
// Combination of cumulative sum and mask?
return IntegerSequence<???>();
}
For example, if the input would be
BoolPack<true,false,true,false,true> b;
The function should return
IntegerSequence<1,0,2,0,3> e();
My best guess on how to implement this would be to compute a partial sum
where the the kth template parameter is
K = K-1 + static_cast<size_t>(get<K>(make_tuple<B...>));
I'm not sure if this is the way to do it. Is there not a more direct approach that doesn't require making tuples for example? Applying the recursion should result in
IntegerSequence<1,1,2,2,3> s();
And then to multiply this componentwise with the elements of the original BoolPack. Is this the way to go, or can I do this without tuples?
Thanks!
The way you think to implement
template<bool...B>
constexpr auto enumerate( const BoolPack<B...>& b ) {
// Combination of cumulative sum and mask?
return IntegerSequence<???>();
}
can't work because C++ is a strong typed language, so the returned type can't depend from sums obtained from code that can be executed compile time.
I know that the values are known at compile time, so the values can be computed compile-time; but the best way that I see pass through a specific type traits.
By example (sorry: renamed IntegerSequence as IndexSequence to be more near to the C++14 std::index_sequence)
template <std::size_t, typename, std::size_t ...>
struct BoolIndexer
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<true, Bs...>, Is...>
: public BoolIndexer<N+1U, BoolPack<Bs...>, Is..., N>
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<false, Bs...>, Is...>
: public BoolIndexer<N, BoolPack<Bs...>, Is..., 0U>
{ };
template <std::size_t N, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<>, Is...>
{ using type = IndexSequence<Is...>; };
The following is a full compiling example
#include <iostream>
#include <type_traits>
template <bool ... B>
struct BoolPack
{ };
template<size_t...I>
struct IndexSequence
{ };
template <std::size_t, typename, std::size_t ...>
struct BoolIndexer
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<true, Bs...>, Is...>
: public BoolIndexer<N+1U, BoolPack<Bs...>, Is..., N>
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<false, Bs...>, Is...>
: public BoolIndexer<N, BoolPack<Bs...>, Is..., 0U>
{ };
template <std::size_t N, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<>, Is...>
{ using type = IndexSequence<Is...>; };
int main ()
{
using type1 = BoolPack<true,false,true,false,true>;
using type2 = typename BoolIndexer<1U, type1>::type;
static_assert( std::is_same<type2, IndexSequence<1,0,2,0,3>>{}, "!" );
}
If you really need a function to get the conversion, using the BoolIndexer type traits you can write it simply as follows
template <bool ... Bs>
constexpr auto getIndexSequence (BoolPack<Bs...> const &)
-> typename BoolIndexer<1U, BoolPack<Bs...>>::type
{ return {}; }
and call it in this way
auto is = getIndexSequence(BoolPack<true,false,true,false,true>{});
Another possible solution pass through the creation of a constexpr function
template <bool ... Bs>
constexpr std::size_t getNumTrue (BoolPack<Bs...> const &, std::size_t top)
{
using unused = int[];
std::size_t cnt = -1;
std::size_t ret { 0 };
(void)unused { 0, (++cnt <= top ? ret += Bs : ret, 0)... };
return ret;
}
that can be called to set the template values for IndexSequence; unfortunately the following example use std::make_index_sequence and std::index_sequence that are C++14 (starting from) features
template <bool ... Bs, std::size_t ... Is>
constexpr auto gisH (BoolPack<Bs...> const &,
std::index_sequence<Is...> const &)
-> IndexSequence<(Bs ? getNumTrue(BoolPack<Bs...>{}, Is) : 0U)...>
{ return {}; }
template <bool ... Bs>
constexpr auto getIndexSequence (BoolPack<Bs...> const & bp)
{ return gisH(bp, std::make_index_sequence<sizeof...(Bs)>{}); }
The following is a full compiling example
#include <utility>
#include <iostream>
#include <type_traits>
template <bool ... B>
struct BoolPack
{ };
template <std::size_t...I>
struct IndexSequence
{ };
template <bool ... Bs>
constexpr std::size_t getNumTrue (BoolPack<Bs...> const &, std::size_t top)
{
using unused = int[];
std::size_t cnt = -1;
std::size_t ret { 0 };
(void)unused { 0, (++cnt <= top ? ret += Bs : ret, 0)... };
return ret;
}
template <bool ... Bs, std::size_t ... Is>
constexpr auto gisH (BoolPack<Bs...> const &,
std::index_sequence<Is...> const &)
-> IndexSequence<(Bs ? getNumTrue(BoolPack<Bs...>{}, Is) : 0U)...>
{ return {}; }
template <bool ... Bs>
constexpr auto getIndexSequence (BoolPack<Bs...> const & bp)
{ return gisH(bp, std::make_index_sequence<sizeof...(Bs)>{}); }
int main()
{
using typeBP = BoolPack<true,false,true,false,true>;
auto is = getIndexSequence(typeBP{});
static_assert( std::is_same<decltype(is),
IndexSequence<1,0,2,0,3>>{}, "!" );
}
I want to be able to do the following:
#include <array>
struct blah { };
template<typename... Args>
constexpr auto foo(Args&&... args)
{
return std::array<blah, sizeof...(Args)>{{ args... }};
}
auto res = foo({}, {});
The following answers aren't satisfying: they just want to check that the parameter pack is of a single type, but I want to convert the values right to it in the arguments (else it does not work).
C++ parameter pack, constrained to have instances of a single type?
Parameter with non-deduced type after parameter pack
Specifying one type for all arguments passed to variadic function or variadic template function w/out using array, vector, structs, etc?
I also can't use initializer_list since I wouldn't be able to count the number of arguments to pass to the array type.
And I especially don't want to type foo(blah{}, blah{});.
What are my possibilities ?
A little bit expanded approach of Jarod42 for lazies (C++17):
#include <utility>
#include <array>
struct blah {};
template <class T, std::size_t I>
using typer = T;
template <class T, std::size_t N, class = std::make_index_sequence<N>>
struct bar_impl;
template <class T, std::size_t N, std::size_t... Is>
struct bar_impl<T, N, std::index_sequence<Is...>> {
static auto foo(typer<T, Is>... ts) {
return std::array<T, N>{{ts...}};
}
};
template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;
template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar_impl<T, Is>... {
using bar_impl<T, Is>::foo...;
};
int main() {
bar<>::foo({}, {});
}
[live demo]
Edit:
Some C++14 solution which (as noted by max66) is even simpler than I expected:
#include <utility>
#include <array>
struct blah {};
template <class T, std::size_t I>
using typer = T;
template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;
template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar<T, N - 1> {
using bar<T, N - 1>::foo;
static auto foo(typer<T, Is>... ts) {
return std::array<T, N>{{ts...}};
}
};
template <class T>
struct bar<T, 0, std::index_sequence<>> {
static auto foo() {
return std::array<T, 0>{{}};
}
};
int main() {
bar<>::foo({}, {});
}
[live demo]
One more edit:
This one (as suggested by Jarod42) provides exactly the same syntax for invocation as in OP's question:
#include <utility>
#include <array>
struct blah {};
template <class T, std::size_t I>
using typer = T;
template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;
template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar<T, N - 1> {
using bar<T, N - 1>::operator();
auto operator()(typer<T, Is>... ts) {
return std::array<T, N>{{ts...}};
}
};
template <class T>
struct bar<T, 0, std::index_sequence<>> {
auto operator()() {
return std::array<T, 0>{{}};
}
};
bar<> foo;
int main() {
foo({}, {});
}
[live demo]
Alright, if you can afford to change the syntax a little bit, this is the best I managed to find:
#include <array>
// to_array implementation taken from
// http://en.cppreference.com/w/cpp/experimental/to_array
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
return { {a[I]...} };
}
}
template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
// End of to_array implementation
struct blah { };
template<std::size_t N>
constexpr auto foo(const blah(&arr)[N])
{
return to_array(arr);
}
int main()
{
auto res = foo({{}, {}});
return 0;
}
As you can see, foo({}, {}) became foo({{}, {}}).
Here is a working example: https://ideone.com/slbKi3
The issue with the way you want it (foo({}, {})) is that the compiler has no way to know what it is supposed to convert {} to.
I tried to find a way to let it know but it didn't listen at all.
If you accept, as proposed by Telokis, to add a bracket level calling foo()
auto res = foo( { {}, {} } );
you can use the C-style array trick proposed by Telokis and a simple cycle to initialize the returned value
template <std::size_t N>
constexpr std::array<blah, N> foo (const blah(&arr)[N])
{
std::array<blah, N> ret;
for ( auto i = 0U ; i < N ; ++i )
ret[i] = arr[i];
return ret;
}
Unfortunately the operator[] for std::array is constexpr only starting from C++17, so the preceding foo is effectively constexpr only starting from C++17.
So you can call
auto res = foo( { {}, {} } );
also in C++11 and C++14, but
constexpr auto res = foo( { {}, {} } );
only starting from C++17.
One (limited) ways to keep your syntax is to have several overloads:
constexpr auto foo(const blah& a1)
{
return std::array<blah, 1>{{ a1 }};
}
constexpr auto foo(const blah& a1, const blah& a2)
{
return std::array<blah, 2>{{ a1, a2 }};
}
// ...
// Up to N
constexpr auto foo(const blah& a1, const blah& a2, .., const blah& aN)
{
return std::array<blah, N>{{ a1, a2, .., aN }};
}
W.F. in his answer shows a way to generate it thanks to variadic at class scope.
In C++17 you can use a combination of static_assert and std::conjunction like this:
#include <array>
#include <type_traits>
struct blah {};
template <typename Arg, typename... Args>
constexpr auto foo_helper(Arg&& first, Args&&... rest) {
static_assert(std::conjunction_v<std::is_same<Arg, Args>...>);
return std::array<blah, 1 + sizeof...(Args)>{first, rest...};
}
template <typename... Args>
constexpr auto foo(Args&&... args) {
return foo_helper(std::forward<Args>(args)...);
}
auto res = foo(blah{}, blah{})
I have to following problem:
template< size_t... N_i >
class A
{
// ...
};
template< size_t N, size_t... N_i >
A</* first N elements of N_i...*/> foo()
{
A</* first N elements of N_i...*/> a;
// ...
return a;
}
int main()
{
A<1,2> res = foo<2, 1,2,3,4>();
return 0;
}
Here, I want foo to have the return type A</* first N size_t of N_i...*/>, i.e., the class A which has as template arguments the first N elements of the parameter pack N_i.
Does anyone know how this can be implemented?
Here is the shortest solution that came to my mind (with two lines spent for an alias).
It follows a minimal, working example based on the code posted by the OP:
#include<functional>
#include<cstddef>
#include<utility>
#include<tuple>
template<std::size_t... V>
class A {};
template<std::size_t... V, std::size_t... I>
constexpr auto func(std::index_sequence<I...>) {
return A<std::get<I>(std::make_tuple(V...))...>{};
}
template<std::size_t N, std::size_t... V>
constexpr auto func() {
return func<V...>(std::make_index_sequence<N>{});
}
template<std::size_t N, std::size_t... V>
using my_a = decltype(func<N, V...>());
int main() {
A<1,2> res1 = func<2, 1, 2, 3, 4>();
// Or even better...
decltype(func<2, 1, 2, 3, 4>()) res2{};
// Or even better...
my_a<2, 1, 2, 3, 4> res3{};
}
This is a slight variation on #skypjack's answer that avoids using tuples:
template <size_t... N_i,size_t... M_i>
auto foo2(std::index_sequence<M_i...>)
{
constexpr size_t values[] = {N_i...};
return A<values[M_i]...>();
}
template <size_t N,size_t... N_i>
auto foo()
{
return foo2<N_i...>(std::make_index_sequence<N>());
}
The most direct subproblem is in the land of typelists:
template <class... Ts>
struct typelist {
using type = typelist;
static constexpr std::size_t size = sizeof...(Ts);
};
template <class T>
struct tag { using type = T; };
template <std::size_t N, class TL>
struct head_n {
using type = ???;
};
Now, head_n is just a matter of simple recursion - move an element from one list to another list N times starting from an empty list.
template <std::size_t N, class R, class TL>
struct head_n_impl;
// have at least one to pop from and need at least one more, so just
// move it over
template <std::size_t N, class... Ts, class U, class... Us>
struct head_n_impl<N, typelist<Ts...>, typelist<U, Us...>>
: head_n_impl<N-1, typelist<Ts..., U>, typelist<Us...>>
{ };
// we have two base cases for 0 because we need to be more specialized
// than the previous case regardless of if we have any elements in the list
// left or not
template <class... Ts, class... Us>
struct head_n_impl<0, typelist<Ts...>, typelist<Us...>>
: tag<typelist<Ts...>>
{ };
template <class... Ts, class U, class... Us>
struct head_n_impl<0, typelist<Ts...>, typelist<U, Us...>>
: tag<typelist<Ts...>>
{ };
template <std::size_t N, class TL>
using head_n = typename head_n_impl<N, typelist<>, TL>::type;
Going from this to your specific problem I leave as an exercise to the reader.
An alternate approach is via concatenation. Convert every element of a typelist<Ts...> into either a typelist<T> or a typelist<>, and then concat them all together. concat is straightforward:
template <class... Ts>
struct concat { };
template <class TL>
struct concat<TL>
: tag<TL>
{ };
template <class... As, class... Bs, class... Rest>
struct concat<typelist<As...>, typelist<Bs...>, Rest...>
: concat<typelist<As..., Bs...>, Rest...>
{ };
And then we can do:
template <std::size_t N, class TL, class = std::make_index_sequence<TL::size>>
struct head_n;
template <std::size_t N, class... Ts, std::size_t... Is>
struct head_n<N, typelist<Ts...>, std::index_sequence<Is...>>
: concat<
std::conditional_t<(Is < N), typelist<Ts>, typelist<>>...
>
{ };
template <std::size_t N, class TL>
using head_n_t = typename head_n<N, TL>::type;
The advantage of this latter approach is that concat can be replaced in C++17 by a fold-expression given an appropriate operator+:
template <class... As, class... Bs>
constexpr typelist<As..., Bs...> operator+(typelist<As...>, typelist<Bs...> ) {
return {};
}
which allows:
template <std::size_t N, class... Ts, std::size_t... Is>
struct head_n<N, typelist<Ts...>, std::index_sequence<Is...>>
{
using type = decltype(
(std::conditional_t<(Is < N), typelist<Ts>, typelist<>>{} + ... + typelist<>{})
);
};
This is fairly simple with Boost.Hana:
namespace hana = boost::hana;
template<size_t... vals>
auto make_a(hana::tuple<hana::integral_constant<size_t, vals>...>)
{
return A<vals...>{};
}
template<size_t N, size_t... vals>
auto foo(){
constexpr auto front = hana::take_front(
hana::tuple_c<size_t, vals...>,
hana::integral_c<size_t,N>
);
return detail::make_a(front);
}
live demo
You could also make use of variadic generic lambda expression and reusable helper structure to perform compile-time iteration:
#include <utility>
#include <tuple>
template <std::size_t N, class = std::make_index_sequence<N>>
struct iterate;
template <std::size_t N, std::size_t... Is>
struct iterate<N, std::index_sequence<Is...>> {
template <class Lambda>
auto operator()(Lambda lambda) {
return lambda(std::integral_constant<std::size_t, Is>{}...);
}
};
template <size_t... Is>
struct A { };
template <size_t N, size_t... Is>
auto foo() {
return iterate<N>{}([](auto... ps){
using type = std::tuple<std::integral_constant<std::size_t, Is>...>;
return A<std::tuple_element_t<ps, type>{}...>{};
});
}
int main() {
decltype(foo<3, 1, 2, 3, 4>()) a; // == A<1, 2, 3> a;
}
Unfortunately, such method requires to define additional Helper types
template< size_t... N_i >
class A
{
};
template <size_t... N_i>
struct Helper;
template <size_t... N_i>
struct Helper<0, N_i...>
{
typedef A<> type;
};
template <size_t N0, size_t... N_i>
struct Helper<1, N0, N_i...>
{
typedef A<N0> type;
};
template <size_t N0, size_t N1, size_t... N_i>
struct Helper<2, N0, N1, N_i...>
{
typedef A<N0, N1> type;
};
template< size_t N, size_t... N_i >
typename Helper<N, N_i...>::type foo()
{
typename Helper<N, N_i...>::type a;
return a;
}
How do I initialize std::array<T, n> if T is not default constructible?
I know it's possible to initialize it like that:
T t{args};
std::array<T, 5> a{t, t, t, t, t};
But n for me is template parameter:
template<typename T, int N>
void f(T value)
{
std::array<T, N> items = ???
}
And even if it wasn't template, it's quite ugly to repeat value by hand if n is too large.
Given N, you could generate a sequence-type calledseq<0,1,2,3,...N-1> using a generator called genseq_t<>, then do this:
template<typename T, int N>
void f(T value)
{
//genseq_t<N> is seq<0,1,...N-1>
std::array<T, N> items = repeat(value, genseq_t<N>{});
}
where repeat is defined as:
template<typename T, int...N>
auto repeat(T value, seq<N...>) -> std::array<T, sizeof...(N)>
{
//unpack N, repeating `value` sizeof...(N) times
//note that (X, value) evaluates to value
return {(N, value)...};
}
And the rest is defined as:
template<int ... N>
struct seq
{
using type = seq<N...>;
static const std::size_t size = sizeof ... (N);
template<int I>
struct push_back : seq<N..., I> {};
};
template<int N>
struct genseq : genseq<N-1>::type::template push_back<N-1> {};
template<>
struct genseq<0> : seq<> {};
template<int N>
using genseq_t = typename genseq<N>::type;
Online demo
Hope that helps.
Sadly the existing answers here don't work for non-copyable types. So I took #Nawaz answer and modified it:
#include <utility>
#include <array>
template<typename T, size_t...Ix, typename... Args>
std::array<T, sizeof...(Ix)> repeat(std::index_sequence<Ix...>, Args &&... args) {
return {{((void)Ix, T(args...))...}};
}
template<typename T, size_t N>
class initialized_array: public std::array<T, N> {
public:
template<typename... Args>
initialized_array(Args &&... args)
: std::array<T, N>(repeat<T>(std::make_index_sequence<N>(), std::forward<Args>(args)...)) {}
};
Note that this is an std::array subclass so that one can easily write
class A {
A(int, char) {}
}
...
class C {
initialized_array<A, 5> data;
...
C(): data(1, 'a') {}
}
Without repeating the type and size. Of course, this way can also be implemented as a function initialize_array.
Following will solve your issue:
#if 1 // Not in C++11, but in C++1y (with a non linear better version)
template <std::size_t ...> struct index_sequence {};
template <std::size_t I, std::size_t ...Is>
struct make_index_sequence : make_index_sequence<I - 1, I - 1, Is...> {};
template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
#endif
namespace detail
{
template <typename T, std::size_t ... Is>
constexpr std::array<T, sizeof...(Is)>
create_array(T value, index_sequence<Is...>)
{
// cast Is to void to remove the warning: unused value
return {{(static_cast<void>(Is), value)...}};
}
}
template <std::size_t N, typename T>
constexpr std::array<T, N> create_array(const T& value)
{
return detail::create_array(value, make_index_sequence<N>());
}
So test it:
struct NoDefaultConstructible {
constexpr NoDefaultConstructible(int i) : m_i(i) { }
int m_i;
};
int main()
{
constexpr auto ar1 = create_array<10>(NoDefaultConstructible(42));
constexpr std::array<NoDefaultConstructible, 10> ar2 = create_array<10>(NoDefaultConstructible(42));
return 0;
}
Inspired by #Nawaz, this is more concise and makes better use of the standard: https://godbolt.org/z/d6a7eq8T5
#include <array>
#include <type_traits>
#include <fmt/format.h>
#include <fmt/ranges.h>
// Inspired by https://stackoverflow.com/a/18497366/874660
//! Return a std::array<T, Sz> filled with
//! calls to fn(i) for i in the integer sequence:
template <typename Int, Int...N, typename Fn>
[[nodiscard]] constexpr auto transform_to_array(std::integer_sequence<Int, N...>, Fn fn) {
return std::array{(static_cast<void>(N), fn(N))...};
}
//! Repeated application of nullary fn:
template <std::size_t N, typename Fn>
[[nodiscard]] constexpr auto generate_n_to_array(Fn fn) -> std::array<decltype(fn()), N> {
return transform_to_array(std::make_integer_sequence<std::size_t, N>(), [&](std::size_t) { return fn(); });
}
int main() {
static constexpr std::array<int, 3> a = generate_n_to_array<3>([i = 0]() mutable { return 2 * (i++); });
fmt::print("{}\n", a);
}
There are already many great answers, so a single remark:
most of them use N twice: once in the array<T,N> and once in the repeat/genseq/generate/whatever you call it...
Since we are using a single value anyway, it seems we can avoid repeating the size twice, here's how:
#include <iostream>
#include <array>
#include <type_traits>
// Fill with a value -- won't work if apart from non-default-constructible, the type is also non-copyable...
template <typename T>
struct fill_with {
T fill;
constexpr fill_with(T value) : fill{value} {}
template <typename... Args>
constexpr fill_with(std::in_place_type_t<T>, Args&&... args) : fill{ T{std::forward<Args>(args)...} } {}
template <typename U, size_t N>
constexpr operator std::array<U, N> () {
return [&]<size_t... Is>(std::index_sequence<Is...>) {
return std::array{ ((void)Is, fill)... };
}(std::make_index_sequence<N>{});
}
};
// A little more generic, but requires C++17 deduction guides, otherwise using it with lambdas is a bit tedious
template <typename Generator>
struct construct_with {
Generator gen;
template <typename F> constexpr construct_with(F && f) : gen{std::forward<F>(f)} {}
template <typename U, size_t N>
constexpr operator std::array<U, N> () {
return [&]<size_t... Is>(std::index_sequence<Is...>) {
return std::array{ ((void)Is, gen())... };
}(std::make_index_sequence<N>{});
}
};
template <typename F>
construct_with(F&&) -> construct_with<F>;
struct A {
A(int){}
A(A const&) = delete;
};
int main() {
std::array<int, 7> arr = fill_with<int>{ 7 };
std::array<int, 7> arr = fill_with{ 7 }; // Ok since C++17
// or you can create a maker function to wrap it in pre-c++17 code, as usual.
std::array<A, 7> as = construct_with{[]{ return A{7}; }};
for (auto & elem : arr) std::cout << elem << '\n';
}
Note: Here I used a few C++20 constructs, which may or may not be an issue in your case, but changing from one to the other is pretty straight-forward
I'd also recommend using <type_traits> and std::index_sequence and all the other sequences from the std if possible to avoid reinventing the wheel)