I'd like to write a constexpr template function that permutes elements of an array passed in as a parameter. So I've come up with something like this:
template <typename T, std::size_t N, typename... Ts>
constexpr std::array<T, N> permute(const std::array<T, N>& arr, const std::array<int, N>& permutation, Ts&&... processed)
{
return (sizeof...(Ts) == N) ?
std::array<T, N>{ std::forward<Ts>(processed)... } :
permute(arr, permutation, std::forward<Ts>(processed)..., arr[permutation[sizeof...(Ts)]]);
}
Usage example:
constexpr std::array<int, 3> arr{ 1, 2, 3 };
constexpr std::array<int, 3> permutation{ 2, 1, 0 };
constexpr auto result = permute(arr, permutation); //result should contain { 3, 2, 1 }
The problem is the above code doesn't compile. For some reason g++ 6.4 tries to instantiate the permute template with 4 and more parameters hidden under 'processed' template parameter pack.
Can you help me correct my code and make it compile?
Full code
I'll present a "quick fix" that demonstrates the cause of the problem, then show how to solve the problem in C++11. After that, I'll show how to use newer features (C++14 onward) to get a simpler implementation.
Diagnosis
The cause of your runaway compilation is that the compiler has to generate both branches of the conditional and check them for correctness, even though it could prove that one of them will never be evaluated.
In newer versions of C++, we can make it work by replacing the ? with an if constexpr:
#include <array>
#include <cstddef>
#include <utility>
template <typename T, std::size_t N, typename... Ts>
constexpr std::array<T, N> permute(const std::array<T, N>& arr,
const std::array<int, N>& permutation,
Ts&&... processed)
{
if constexpr (sizeof...(Ts) == N)
return std::array<T, N>{ std::forward<Ts>(processed)... };
else
return permute(arr, permutation, std::forward<Ts>(processed)...,
arr[permutation[sizeof...(Ts)]]);
}
int main()
{
constexpr std::array<int, 3> arr{ 1, 2, 3 };
constexpr std::array<int, 3> permutation{ 2, 1, 0 };
constexpr auto result = permute(arr, permutation);
return result != std::array<int, 3>{ 3, 2, 1 };
}
(For these newer versions of C++, this can be simplified further using std::index_sequence, as I'll show later).
C++11 code
C++11 doesn't have if constexpr, so we'll need to revert to SFINAE instead:
#include <array>
#include <cstddef>
#include <utility>
template <typename T, std::size_t N, typename... Ts>
constexpr typename std::enable_if<sizeof...(Ts) == N, std::array<T, N> >::type
permute(const std::array<T, N>&, const std::array<int, N>&,
Ts&&... processed)
{
return std::array<T, N>{ std::forward<Ts>(processed)... };
}
template <typename T, std::size_t N, typename... Ts>
constexpr typename std::enable_if<sizeof...(Ts) != N, std::array<T, N> >::type
permute(const std::array<T, N>& arr, const std::array<int, N>& permutation,
Ts&&... processed)
{
return permute(arr, permutation, std::forward<Ts>(processed)...,
arr[permutation[sizeof...(Ts)]]);
}
Here, we provide completely separate functions for sizeof...(Ts) == N and sizeof...(Ts) != N, and use std::enable_if to select between them.
C++14 onwards
If we're able to use C++14 or later, we get std::index_sequence, which greatly simplifies operating on all the elements of an array or tuple. This still requires two functions, but this time one of them calls the other, and the logic is a bit easier to follow:
#include <array>
#include <cstddef>
#include <utility>
template<typename T, std::size_t N, std::size_t... I>
constexpr std::array<T, N>
permute_impl(const std::array<T, N>& a, const std::array<int, N>& p,
std::index_sequence<I...>)
{
return { a[p[I]]... };
}
template<typename T, std::size_t N, typename I = std::make_index_sequence<N>>
constexpr std::array<T, N>
permute(const std::array<T, N>& a, const std::array<int, N>& p)
{
return permute_impl(a, p, I{});
}
It might even be worth implementing your own index_sequence if you need this more than once and you're constrained to using only C++11.
Related
Since I was not able to find such a function (incorrectly?), I'm trying to make a compile-time function (constexpr) function which takes a std::array<T,n> arr and a T t and returns a new std::array<T,n+1> with t added to the end of arr. I've started with something like this:
template <typename T, int n>
constexpr std::array<T,n+1> append(std::array<T,n> a, T t);
template <typename T>
constexpr std::array<T,1> append(std::array<T,0> a, T t)
{
return std::array<T,1>{t};
}
template <typename T>
constexpr std::array<T,2> append(std::array<T,1> a, T t)
{
return std::array<T,2>{a[0], t};
}
Here I get stuck. What I need is a way to expand a in the first n places of the initializer list, and then add t add the end. Is that possible? Or is there another way of doing this?
Of course, it is possible: std::index_sequence<I...> is your friend! You'd simply dispatch to a function which takes a suitable std::index_sequence<I...> as argument and expands the pack with all the values. For example:
template <typename T, std::size_t N, std::size_t... I>
constexpr std::array<T, N + 1>
append_aux(std::array<T, N> a, T t, std::index_sequence<I...>) {
return std::array<T, N + 1>{ a[I]..., t };
}
template <typename T, std::size_t N>
constexpr std::array<T, N + 1> append(std::array<T, N> a, T t) {
return append_aux(a, t, std::make_index_sequence<N>());
}
It was easy to extend Dietmar's answer to a util that lets you constexpr- catenate two arrays:
// constexpr util to catenate two array's.
//
// Usage:
//
// constexpr std::array<int, 2> a1 = { 1, 2 };
// constexpr std::array<int, 2> a2 = { 3, 4 };
//
// constexpr auto a3 = catenate_array(a1, a2);
template <typename T, std::size_t N, std::size_t M, std::size_t... I, std::size_t... J>
constexpr std::array<T, N + M>
catenate_array_aux(std::array<T, N> a1, std::array<T, M> a2, std::index_sequence<I...>, std::index_sequence<J...>) {
return std::array<T, N + M>{ a1[I]..., a2[J]... };
}
template <typename T, std::size_t N, std::size_t M>
constexpr std::array<T, N + M> catenate_array(std::array<T, N> a1, std::array<T, M> a2) {
return catenate_array_aux(a1, a2, std::make_index_sequence<N>(), std::make_index_sequence<M>());
}
I want to create a function that takes array of strings and converts it to tuple by doing lexical_cast on each of array elements.
std::array size is the same as std::tuple size and all tuple types are known at compile time
For example:
std::tuple<int, double> Result = Convert({"1", "1.0"});
or
int A, B;
std::tie(A, B) = Convert({"1", "2"});
How can I do that with acceptable performace and without c++14 support?
You may do
namespace detail
{
template <typename ... Ts, std::size_t N, std::size_t...Is>
std::tuple<Ts...>
Convert(const std::array<std::string, N>& s,
std::index_sequence<Is...>)
{
return std::tuple<Ts...>{boost::lexical_cast<Ts>(s[Is])...};
}
}
template <typename ... Ts, std::size_t N>
std::tuple<Ts...> Convert(const std::array<std::string, N>& s)
{
static_assert(N == sizeof...(Ts), "Unexpected size");
return detail::Convert<Ts...>(s, std::index_sequence_for<Ts...>());
}
With usage:
std::array<std::string, 2u> ns = {"1", "4.2"};
auto t = Convert<int, double>(ns);
Demo
You'll have to provide the types you want to convert into. As in:
std::tuple<int, double> Result = Convert<int, double>({"1", "1.0"});
With that, it's not so bad:
template <typename... Ts>
std::tuple<Ts...> Convert(const std::array<std::string, sizeof... (Ts)>& arr ) {
return Convert<Ts...>(arr, make_index_sequence<sizeof...(Ts)>{} );
}
template <typename... Ts, typename... Is>
std::tuple<Ts...> Convert(const std::array<std::string, sizeof... (Ts)>& arr, index_sequence<Is...> ) {
return std::make_tuple(boost::lexical_cast<Ts>(arr[Is])...));
}
There are several C++11 implementations of the index sequence trick on SO.
Trying to search for this answer, I noticed that the titles of the questions
on variadic template functions are very uninformative when searching on
SO. You only known that the question is about variadic template. Hopefully my
question wasn't asked before and the title will help people finding it.
So, I want to make a function which has a variadic template parameter. More
precisely, as an example, let say I want to have a compile time permutation of
an array. Here is a working code:
template <typename... Ts> struct Sequence {};
template <typename T, unsigned Size, typename... SeqTis> struct Permute;
template <typename T, unsigned Size, typename... SeqTis>
struct Permute<T, Size, Sequence<SeqTis...> > {
using type = typename std::array<T, Size>;
constexpr static type permute(const type ar) {
return { (ar[SeqTis::value])... };
}
};
Then the following is perfectly legal:
using T0 = std::integral_constant<int, 0>;
using T1 = std::integral_constant<int, 1>;
using T2 = std::integral_constant<int, 2>;
using Perm120 = Permute<int, 3, Sequence<T1, T2, T0> >;
using arr3 = Perm120::type;
constexpr arr3 ar {5,7,2};
constexpr arr3 arPerm = Perm120::permute(ar);
I'm now trying to avoid using a structure so I wrote the following:
template <typename T, unsigned Size, typename... SeqTis>
constexpr typename std::array<T, Size>
permutefun<T, Size, Sequence<SeqTis...> >(const typename std::array<T, Size> ar) {
return { (ar[SeqTis::value])... };
}
And GCC refuse it saying that
essai.cpp:19:11: error: expected initializer before ‘<’ token
permutefun<T, Size, Sequence<SeqTis...> >(const typename std::array<T, Size> ar) {
^
Why is it so ?
To add to previous answers, you also need to have a convenient syntax for calling permutefun, but the current template parameters
template <typename T, unsigned Size, typename... SeqTis>
are not convenient because you'd have to call
permutefun <int, 3, T1, T2, T0>(ar);
A solution is to deduce arguments in two steps:
#include <array>
template <typename... Ts> struct Sequence {};
template <typename... SeqTis, typename T, unsigned long Size>
constexpr std::array<T, Size>
permutefun(Sequence<SeqTis...>, const std::array<T, Size> ar) {
return { (ar[SeqTis::value])... };
}
template <typename Seq, typename T, unsigned long Size>
constexpr std::array<T, Size>
permutefun(const std::array<T, Size> ar) {
return permutefun(Seq(), ar);
}
int main ()
{
using T0 = std::integral_constant<int, 0>;
using T1 = std::integral_constant<int, 1>;
using T2 = std::integral_constant<int, 2>;
using Perm120 = Sequence<T1, T2, T0>;
using arr3 = std::array <int, 3>;
constexpr arr3 ar = {5,7,2};
constexpr arr3 arPerm = permutefun <Perm120>(ar);
}
Now arguments T, Size appear last so are automatically deduced by the input array. Argument Seq comes first, but to deduce its "unpacked" parameters SeqTis... you need a call to a second overload of permutefun. This allows the convenient syntax
permutefun <Perm120>(ar);
The 2nd overload may be useful by itself, because it allows the alternative syntax
Perm120 perm;
permutefun(perm, ar);
Also note that std::array::operator[] is constexpr only in C++14. For instance, this does not compile with Clang 3.3 and -std=c++11.
Your syntax looks like an attempt at a partial function specialisation, but that's not what you want, so that's not what you should write. Since partial function specialisations aren't supported, the compiler gets confused by the unexpected <.
template <typename T, unsigned Size, typename... SeqTis>
constexpr std::array<T, Size>
permutefun(const std::array<T, Size> ar) {
// ^ removed the <...>
return { (ar[SeqTis::value])... };
}
Also, you don't need typename here, as std::array<T, Size> is already known to be a type. It's fine to leave it in, but it works just as well without it.
Do you mean:
template <typename T, unsigned Size, typename... SeqTis>
constexpr std::array<T, Size>
permutefun(const typename std::array<T, Size> ar) {
return { (ar[SeqTis::value])... };
}
partial template specialization is not possible for function.
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)
Is there a way in C++11 to cast an array of one type to another data type at compile-time :
#include <iostream>
#include <array>
#include <type_traits>
int main()
{
static constexpr std::array<double, 3> darray{{1.5, 2.5, 3.5}};
static constexpr std::array<int, 3> iarray(darray); // not working
// Is there a way to cast an array to another data type ?
return 0;
}
No, but you can do it by hand fairly easily using the indices trick, assuming the implementation provides constexpr std::get (or equivalently a constexpr overload of operator[]):
#include <iostream>
#include <array>
#include <type_traits>
// http://loungecpp.wikidot.com/tips-and-tricks%3aindices
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...>: indices<Is...> {};
template<typename T, typename U, size_t i, size_t... Is>
constexpr auto array_cast_helper(
const std::array<U, i> &a, indices<Is...>) -> std::array<T, i> {
return {{static_cast<T>(std::get<Is>(a))...}};
}
template<typename T, typename U, size_t i>
constexpr auto array_cast(
const std::array<U, i> &a) -> std::array<T, i> {
// tag dispatch to helper with array indices
return array_cast_helper<T>(a, build_indices<i>());
}
int main() {
static constexpr std::array<double, 3> darray{{1.5, 2.5, 3.5}};
static constexpr std::array<int, 3> iarray = array_cast<int>(darray);
}
If your implementation doesn't provide constexpr get or operator[], you can't use array as there's no current standard way to access array elements constexpr; your best bet is to use your own implementation of array with the constexpr extensions.
The constexpr library additions are proposed for addition to the standard in n3470.
Instead of an unmaintainable mess of cryptic template code that won't even currently compile with the most commonly used C++ compiler, and avoiding ungood redundancy in the number specs, simply use a macro:
#include <iostream>
#include <array>
#include <type_traits>
#define MY_VALUES( T ) {T(1.5), T(2.5), T(3.5)}
int main()
{
static constexpr std::array<double, 3> darray = { MY_VALUES( double ) };
static constexpr std::array<int, 3> iarray = { MY_VALUES( int ) };
// Whatever...
}
This is the kind of stuff macros are good at.
Just make sure to minimize the possibility of name collision by using an all uppercase macro name, and maybe some custom prefix.
General advice: don't be too clever, keep it simple.
Keep in mind, someone has to maintain it later.
I've found a very simple solution with a single variadic function:
#include <iostream>
#include <array>
#include <type_traits>
template<typename Type, typename OtherType, std::size_t Size, typename... Types, class = typename std::enable_if<sizeof...(Types) != Size>::type>
constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data);
template<typename Type, typename OtherType, std::size_t Size, typename... Types, class = typename std::enable_if<sizeof...(Types) == Size>::type, class = void>
constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data);
template<typename Type, typename OtherType, std::size_t Size, typename... Types, class>
constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data)
{
return convert<Type>(source, data..., static_cast<const Type>(source[sizeof...(data)]));
}
template<typename Type, typename OtherType, std::size_t Size, typename... Types, class, class>
constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data)
{
return std::array<Type, Size>{{data...}};
}
int main()
{
static constexpr std::array<double, 3> darray{{1., 2., 3.}};
static constexpr std::array<int, 3> iarray = convert<int>(darray);
std::cout<<(std::integral_constant<int, iarray[2]>())<<std::endl;
return 0;
}
You cannot cast, but you can copy:
static constexpr std::array<double, 3> darray{{1.5, 2.5, 3.5}};
std::array<int, 3> iarray;
std::copy(begin(darray), end(darray), begin(iarray));
Unfortunately iarray cannot be constexpr any more in this case.