Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 initialize array with uniform value in constexpr function

I have a class template which builds a simple array based on the template parameters as one of its members. I need to be able to initialize every element in the array to a single value in one of the constructors. Unfortunately this constructor must be constexpr.

The relevant part boils down to:

template <typename T, size_t N>
class foo
{
  T data[N];

  constexpr foo(T val)
  {
    // initialize data with N copies of val
  }
};

Using std::fill or a loop is incompatible with the constexpr requirement. Initializing with : data{val} only sets the first element of the array and zero-initializes the remainder.

How can this be achieved?

I feel like there should be a solution with variadic templates and tuples etc...

like image 282
marack Avatar asked May 28 '14 01:05

marack


People also ask

Can I call a constexpr function inside an array declaration?

But with constexpr, you can now use a call to a constexpr function inside an array declaration: A constexpr function has some very rigid rules it must follow:

What is constexpr in C++ 11?

The idea is to spend time in compilation and save time at run time (similar to template metaprogramming ). constexpr specifies that the value of an object or a function can be evaluated at compile-time and the expression can be used in other constant expressions. In C++ 11, a constexpr function should contain only one return statement.

What is the difference between C++ 11 and C++ 14 constexpr?

In C++ 11, a constexpr function should contain only one return statement. C++ 14 allows more than one statement. constexpr function should refer only to constant global variables. constexpr function can call only other constexpr function not simple function.

What is a constexpr variable in C++?

A constexpr specifier used in a function or static data member (since C++17) declaration implies inline. If any declaration of a function or function template has a constexpr specifier, then every declaration must contain that specifier. A constexpr variable must satisfy the following requirements:


2 Answers

Rather curiously, a solution for the problem exists in c++14 (compile the example with -std=c++1y on gcc; also see comments for a bit more verbose c++11 solution by Praetorian):

template <size_t N>
struct bar {
    template <typename T, typename ...Tn>
    static constexpr auto apply(T v, Tn ...vs)
    {
        return bar<N - 1>::apply(v, v, vs...);
    }
};

template <>
struct bar<1> {
    template <typename T, typename ...Tn>
    static constexpr auto apply(T v, Tn ...vs)
    {
        return std::array<T, sizeof...(vs) + 1>{v, vs...};
    }

};

template <typename T, size_t N>
struct foo {
    std::array<T, N> data;

    constexpr foo(T val)
    : data(bar<N>::apply(val))
    {}
};

(I replaced the POD array with std::array - suppose it should not make any problems for your use case).

Live example is here: http://coliru.stacked-crooked.com/a/4731a10ee54563b9

like image 127
oakad Avatar answered Sep 19 '22 23:09

oakad


You may use the following: (https://ideone.com/xTacMP)

namespace detail
{
    template <typename T, std::size_t...Is>
    constexpr std::array<T, sizeof...(Is)> make_array(T val, index_sequence<Is...>)
    {
        return {(static_cast<void>(Is), val)...};
    }
}

template <std::size_t N, typename T>
constexpr std::array<T, N> make_array(T val)
{
    return detail::make_array(val, make_index_sequence<N>());
}

And then call it:

constexpr foo(T val) : data(make_array<N>(val)) {}
like image 40
Jarod42 Avatar answered Sep 18 '22 23:09

Jarod42