C++: Can I have non-static member variable templates? - c++

I'm trying to write a bit of code that requires me to have a lot of std::arrays in a container class. These arrays are all of varying sizes (all consecutive from 2-16, if that matters), and there is exactly one of each size. I want to put them in a container class, and be able to access them with templates.
It's probably easier to explain with code. I want something like this:
class ContainerClass {
public:
// I want to declare some number of arrays right here, all of different
// sizes, ranging from 2-16. I'd like to be able to access them as
// arr<2> through arr<16>.
// This code gives a compiler error, understandably.
// But this is what I'd think it'd look like.
template <size_t N> // I also need to find a way to restrict N to 2 through 16.
std::array<int, N> arr;
// An example method of how I want to be able to use this.
template <size_t N>
void printOutArr() {
for (int i = 0; i < N; i++) {
std::cout << arr<N>[i] << std::endl;
}
}
};
I'd like the code to expand out as if it just had 15 arrays in it, from 2-16. Like this, but with templates:
class ContainerClass {
public:
std::array<int, 2> arr2;
std::array<int, 3> arr3;
std::array<int, 4> arr4;
std::array<int, 5> arr5;
// ... and so on.
};
From what I understand, C++ supports variable templates, but it seems like it's only for static members in classes. Is there an alternative that could behave similarly (preferably with as little overhead as possible)?
If you need more information, please ask.
Thanks in advance.

Can I have non-static member variable templates?
No.
However, you can use templates to generate a list of members like you describe. Here is an example using recursive inheritance:
template<class T, std::size_t base, std::size_t size>
class Stair;
template<class T, std::size_t base>
class Stair<T, base, base> {};
template<class T, std::size_t base, std::size_t size>
class Stair : Stair<T, base, size - 1> {
protected:
std::array<T, size> arr;
public:
template<std::size_t s>
std::array<T, s>& array() {
return Stair<T, base, s>::arr;
}
};
int main()
{
Stair<int, 2, 10> s;
auto& arr = s.array<9>();

I think I may have a solution using recursive templates and std::tuple. I compiled and tested it using gcc 7.3.0.
This makes me feel dirty, but it seems to work.
#include <iostream>
#include <array>
#include <tuple>
#include <type_traits>
// Forward declare A since there is a circular dependency between A and Arrays
template <size_t size, size_t start, typename... T>
struct A;
// If size is greater than start define a type that is an A::ArrayTuple from the
// next step down (size - 1) otherwise type is void
template <size_t size, size_t start, typename E, typename... T>
struct Arrays {
using type = typename std::conditional<(size > start),
typename A<size-1, start, E, T...>::ArrayTuple,
void
>::type;
};
// Use template recursion to begin at size and define std::array<int, size>
// to add to a tuple and continue marching backwards (size--) until size == start
// When size == start take all of the std::arrays and put them into a std::tuple
//
// A<size, start>::ArrayTuple will be a tuple of length (size - start + 1) where
// the first element is std::array<int, start>, the second element is
// std::array<int, start + 1> continuing until std::array<int, size>
template <size_t size, size_t start, typename... T>
struct A {
using Array = typename std::array<int, size>;
using ArrayTuple = typename std::conditional<(size == start),
typename std::tuple<Array, T...>,
typename Arrays<size, start, Array, T...>::type
>::type;
};
// This specialization is necessary to avoid infinite template recursion
template <size_t start, typename... T>
struct A<0, start, T...> {
using Array = void;
using ArrayTuple = void;
};
template <size_t size, size_t start = 1>
class Container {
public:
using ArrayTuple = typename A<size, start>::ArrayTuple;
// Shorthand way to the get type of the Nth element in ArrayTuple
template <size_t N>
using TupleElementType = typename
std::tuple_element<N-start, ArrayTuple>::type;
ArrayTuple arrays_;
// Returns a reference to the tuple element that has the type of std::array<int, N>
template <size_t N>
TupleElementType<N>& get_array() {
// Static assertion that the size of the array at the Nth element is equal to N
static_assert(std::tuple_size< TupleElementType<N> >::value == N);
return std::get<N-start>(arrays_);
}
// Prints all elements of the tuple element that has the type of std::array<int, N>
template <size_t N>
void print_array() {
auto& arr = get_array<N>();
std::cout << "Array Size: " << arr.size() << std::endl;
for (int i = 0; i < arr.size(); i++) {
std::cout << arr[i] << std::endl;
}
}
};
int main() {
// Create a new Container object where the arrays_ member will be
// a tuple with 15 elements:
// std::tuple< std::array<int, 2>, std::array<int, 3> ... std::array<int, 16> >
Container<16,2> ctr;
auto& arr2 = ctr.get_array<2>();
arr2[0] = 20;
arr2[1] = 21;
//ctr.print_array<1>(); // Compiler error since 1 < the ctr start (2)
ctr.print_array<2>(); // prints 20 and 21
ctr.print_array<3>(); // prints 3 zeros
ctr.print_array<16>(); // prints 16 zeros
//ctr.print_array<17>(); // Compiler error since 17 > the ctr size (16)
//int x(ctr.arrays_); // Compiler error - uncomment to see the type of ctr.arrays_
return 0;
}
Here's the output from the compiler if I uncomment that line where I try to declare int x showing the type of ctr.arrays_:
so.cpp: In function ‘int main()’:
so.cpp:90:22: error: cannot convert ‘Container<16, 2>::ArrayTuple {aka std::tuple<std::array<int, 2>, std::array<int, 3>, std::array<int, 4>, std::array<int, 5>, std::array<int, 6>, std::array<int, 7>, std::array<int, 8>, std::array<int, 9>, std::array<int, 10>, std::array<int, 11>, std::array<int, 12>, std::array<int, 13>, std::array<int, 14>, std::array<int, 15>, std::array<int, 16> >}’ to ‘int’ in initialization
int x(ctr.arrays_); // Compiler error - uncomment to see the type of ctr.arrays_

Related

Variadic template. Size of the template arguement list in variadic template data structure [duplicate]

How can I get a count of the number of arguments to a variadic template function?
ie:
template<typename... T>
void f(const T&... t)
{
int n = number_of_args(t);
...
}
What is the best way to implement number_of_args in the above?
Just write this:
const std::size_t n = sizeof...(T); //you may use `constexpr` instead of `const`
Note that n is a constant expression (i.e known at compile-time), which means you may use it where constant expression is needed, such as:
std::array<int, n> a; //array of n elements
std::array<int, 2*n> b; //array of (2*n) elements
auto middle = std::get<n/2>(tupleInstance);
Note that if you want to compute aggregated size of the packed types (as opposed to number of types in the pack), then you've to do something like this:
template<std::size_t ...>
struct add_all : std::integral_constant< std::size_t,0 > {};
template<std::size_t X, std::size_t ... Xs>
struct add_all<X,Xs...> :
std::integral_constant< std::size_t, X + add_all<Xs...>::value > {};
then do this:
constexpr auto size = add_all< sizeof(T)... >::value;
In C++17 (and later), computing the sum of size of the types is much simpler using fold expression:
constexpr auto size = (sizeof(T) + ...);
#include <iostream>
template<typename ...Args>
struct SomeStruct
{
static const int size = sizeof...(Args);
};
template<typename... T>
void f(const T&... t)
{
// this is first way to get the number of arguments
constexpr auto size = sizeof...(T);
std::cout<<size <<std::endl;
}
int main ()
{
f("Raje", 2, 4, "ASH");
// this is 2nd way to get the number of arguments
std::cout<<SomeStruct<int, std::string>::size<<std::endl;
return 0;
}

Passing std::array argument with size restricted to expandable set of sizes

How would one best implement a single function that accepts two std::array<int, [size]> arguments, each with a size constrained by a corresponding set of values known at compile-time?
The function must only accept arrays with sizes derived from a given set (enum/macro/etc)
The sets of allowable array "sizes" may be changed in the future and may be large (effectively precluding function overloading)
The function itself should remain fixed regardless of changes to the sets of allowable array "sizes"
The question "Passing a std::array of unknown size to a function", while similar, doesn't appear to directly apply.
The following works in C++14 but seems unnecessarily redundant & messy:
#include <type_traits>
#include <array>
// Add legal/allowable sizes for std::array<> "types" here
// Note: Not married to this; perhaps preprocessor instead?
enum class SizesForArrayX : size_t { Three = 3, Four, Forty = 40 };
enum class SizesForArrayY : size_t { Two = 2, Three, EleventyTwelve = 122 };
// Messy, compile-time, value getter for the above enum classes
template <typename S>
constexpr size_t GetSizeValue(const S size)
{ return static_cast<std::underlying_type_t<S>>(size); }
// An example of the function in question; is Template Argument Deduction
// possible here?
// Note: only arrays of "legal"/"allowable" sizes should be passable
template <SizesForArrayX SX, SizesForArrayY SY>
void PickyArrayHandler(
const std::array<int, GetSizeValue(SX)>& x,
const std::array<int, GetSizeValue(SY)>& y)
{
// Do whatever
for (auto& i : x) i = 42;
for (auto& i : y) while (i --> -41) i = i;
}
Calling the above:
int main()
{
// Declare & (value-)initialize some arrays
std::array<int, GetSizeValue(SizesForArrayX::Forty)> x{};
std::array<int, GetSizeValue(SizesForArrayY::Two>) y{};
//PickyArrayHandler(x, y); // <- Doesn't work; C2672, C2783
// This works & handles arrays of any "allowable" size but the required
// template params are repetitions of the array declarations; ick
PickyArrayHandler<SizesForArrayX::Forty, SizesForArrayY::Two>(x, y);
}
...which is ugly, inelegant, slow-to-compile, and requires the declared array size match the explicit "size" passed to the PickyArrayHandler function template.
For the specific example above: Is there a way for the PickyArrayHandler template to deduce the sizes of the passed arrays?
Generally speaking: Is there a different, better approach?
Since you don't seem to be picky about how the valid sizes are defined, you can use type traits
#include <array>
template <size_t N> struct valid_size1 { enum { value = false }; };
template <size_t N> struct valid_size2 { enum { value = false }; };
template <> struct valid_size1<3> { enum { value = true }; };
template <> struct valid_size1<4> { enum { value = true }; };
template <> struct valid_size1<40> { enum { value = true }; };
template <> struct valid_size2<2> { enum { value = true }; };
template <> struct valid_size2<122> { enum { value = true }; };
template <size_t TX, size_t TY>
void PickyArrayHandler(const std::array<int, TX> &x,
const std::array<int, TY> &y)
{
static_assert(valid_size1<TX>::value, "Size 1 is invalid");
static_assert(valid_size2<TY>::value, "Size 2 is invalid");
// Do whatever
}
int main()
{
// Declare & (value-)initialize some arrays
std::array<int, 40> x{};
std::array<int, 2> y{};
PickyArrayHandler(x, y);
PickyArrayHandler(std::array<int, 4>{}, std::array<int, 2>{});
// PickyArrayHandler(std::array<int, 1>{}, std::array<int, 5>{}); // BOOM!
}
Here's a solution using an array:
#include <iostream>
#include <array>
constexpr size_t valid_1[] = { 3, 4, 40 };
constexpr size_t valid_2[] = { 2, 122 };
template <size_t V, size_t I=0>
struct is_valid1 { static constexpr bool value = V==valid_1[I] || is_valid1<V,I+1>::value; };
template <size_t V, size_t I=0>
struct is_valid2 { static constexpr bool value = V==valid_2[I] || is_valid2<V,I+1>::value; };
template <size_t V>
struct is_valid1<V, sizeof(valid_1)/sizeof(valid_1[0])>
{static constexpr bool value = false; };
template <size_t V>
struct is_valid2<V, sizeof(valid_2)/sizeof(valid_2[0])>
{static constexpr bool value = false; };
template <size_t TX, size_t TY>
void PickyArrayHandler(const std::array<int, TX> &x,
const std::array<int, TY> &y)
{
static_assert(is_valid1<TX>::value, "Size 1 is invalid");
static_assert(is_valid2<TY>::value, "Size 2 is invalid");
// Do whatever
}
twiddled around a bit and got this reduced one working: maybe it helps:
enum SizesForArrayX : size_t { Three = 3, Four, Forty = 40 };
enum SizesForArrayY : size_t { Two = 2, EleventyTwelve = 122 };
template <size_t TX, size_t TY>
void PickyArrayHandler(
const std::array<int, TX>& x,
const std::array<int, TY>& y)
{
// Do whatever
}
int main()
{
// Declare & (value-)initialize some arrays
std::array<int, SizesForArrayX::Forty> x{};
std::array<int, SizesForArrayY::Two> y{};
PickyArrayHandler(x, y);
return 0;
}
Unfortunately, your enums are not continuous so you cannot simply iterate over the enum and you have to handle all cases individually. Since the sizes are known at compile-time you can static_assert for it.
#include <array>
enum SizesForArrayX : size_t { Three = 3, Four, Forty = 40 };
enum SizesForArrayY : size_t { Two = 2, EleventyTwelve = 122 };
template <size_t TX, size_t TY>
void PickyArrayHandler(const std::array<int, TX> &x,
const std::array<int, TY> &y)
{
static_assert(TX == Three || TX == Four || TX == Forty,
"Size mismatch for x");
static_assert(TY == Two || TY == EleventyTwelve, "Size mismatch for y");
// Do whatever
}
int main()
{
// Declare & (value-)initialize some arrays
std::array<int, SizesForArrayX::Forty> x{};
std::array<int, SizesForArrayY::Two> y{};
PickyArrayHandler(x, y);
PickyArrayHandler(std::array<int, 4>{}, std::array<int, 2>{});
//PickyArrayHandler(std::array<int, 1>{}, std::array<int, 5>{}); // BOOM!
}
The best way I see to solve this problem is writing a custom type trait:
template <std::underlying_type_t<SizesForArrayX> SX>
struct is_size_x {
static constexpr bool value = false;
};
template <>
struct is_size_x<static_cast<std::underlying_type_t<SizesForArrayX>>(SizesForArrayX::Forty)>{
static constexpr bool value = true;
};
I'd put these right under the enum class declarations, just so it's easy to check that you got them all. Somebody more clever than I could probably figure out a way to even do this with variadic templates so you only need one specialization.
While tedious, if you have a small set of values this should be fast enough and easy to put in unit tests. The other nice thing about this approach is that if you have multiple functions that need one of these special sizes, you don't have to copy/paste static_asserts around.
With the type traits, your function becomes trivial:
template <std::size_t SX, std::size_t SY>
void PickyArrayHandler(
std::array<int, SX>& x,
std::array<int, SY>& y)
{
static_assert(is_size_x<SX>::value, "Invalid size SX");
static_assert(is_size_y<SY>::value, "Invalid size SY");
// Do whatever
for (auto& i : x) i = 42;
for (auto& i : y) while (i --> -41) i = i;
}
Lastly, you can make a type alias to avoid creating invalid arrays in the first place:
template <typename T, SizesForArrayX SIZE>
using XArray =
std::array<T, static_cast<std::underlying_type_t<SizesForArrayX>>(SIZE)>;
template <typename T, SizesForArrayY SIZE>
using YArray =
std::array<T, static_cast<std::underlying_type_t<SizesForArrayY>>(SIZE)>;
That'll prevent you from declaring an array if it's not an approved size:
XArray<int, SizesForArrayX::Forty> x{};
YArray<int, SizesForArrayY::Two> y{};
Personally I would just manually type the allowable sizes into a static_assert inside PickyArrayHandler. If that's not an option because the sizes will be used in other parts of your program and you're adhering to the DRY principal then I'd use the preprocessor.
#define FOREACH_ALLOWABLE_X(SEP_MACRO) \
SEP_MACRO(3) \
SEP_MACRO(4) \
SEP_MACRO(40) \
#define FOREACH_ALLOWABLE_Y(SEP_MACRO) \
SEP_MACRO(2) \
SEP_MACRO(3) \
SEP_MACRO(122) \
#define COMMA_SEP(NUM) NUM,
#define LOGIC_OR_SEP_X(NUM) N1 == NUM ||
#define LOGIC_OR_SEP_Y(NUM) N2 == NUM ||
#define END_LOGIC_OR false
// some arrays with your sizes incase you want to do runtime checking
namespace allowable_sizes
{
size_t x[] {FOREACH_ALLOWABLE_X(COMMA_SEP)};
size_t y[] {FOREACH_ALLOWABLE_Y(COMMA_SEP)};
}
template <size_t N1, size_t N2>
void PickyArrayHandler(const std::array<int, N1>& x, const std::array<int, N2>& y)
{
static_assert(FOREACH_ALLOWABLE_X(LOGIC_OR_SEP_X) END_LOGIC_OR);
static_assert(FOREACH_ALLOWABLE_Y(LOGIC_OR_SEP_Y) END_LOGIC_OR);
// do whatever
}
#undef FOREACH_ALLOWABLE_X
#undef FOREACH_ALLOWABLE_Y
#undef COMMA_SEP
#undef LOGIC_OR_SEP_X
#undef LOGIC_OR_SEP_Y
#undef END_LOGIC_OR
Some C++ purists will frown at it but it gets the job done.
You could have a is_of_size-like template that check the size of the array, and then use it to disable the template if one of the sizes does not match, something like:
#include <array>
#include <type_traits>
// Forward template declaration without definition.
template <class T, T N, T... Sizes>
struct is_one_of;
// Specialization when there is a single value: Ends of the recursion,
// the size was not found, so we inherit from std::false_type.
template <class T, T N>
struct is_one_of<T, N>: public std::false_type {};
// Generic case definition: We inherit from std::integral_constant<bool, X>, where X
// is true if N == Size or if N is in Sizes... (via recursion).
template <class T, T N, T Size, T... Sizes>
struct is_one_of<T, N, Size, Sizes... >:
public std::integral_constant<
bool, N == Size || is_one_of<T, N, Sizes... >::value> {};
// Alias variable template, for simpler usage.
template <class T, T N, T... Sizes>
constexpr bool is_one_of_v = is_one_of<T, N, Sizes... >::value;
template <std::size_t N1, std::size_t N2,
std::enable_if_t<
(is_one_of_v<std::size_t, N1, 3, 4, 40>
&& is_one_of_v<std::size_t, N2, 2, 3, 122>), int> = 0>
void PickyArrayHandler(
const std::array<int, N1>& x,
const std::array<int, N2>& y)
{
}
Then you can simply:
PickyArrayHandler(std::array<int, 3>{}, std::array<int, 122>{}); // OK
PickyArrayHandler(std::array<int, 2>{}, std::array<int, 3>{}); // NOK
In C++17, you could (I think) replace is_one_of with:
template <auto N, auto... Sizes>
struct is_one_of;
...and automatically deduce std::size_t.
In C++20, you could use a concept to have clearer error messages ;)
Using static_assert for invalid sizes is not a good solution because it doesn't play well with SFINAE; i.e., TMP facilities like std::is_invocable and the detection idiom will return false positives for calls that in fact always yield an error. Far better is to use SFINAE to remove invalid sizes from the overload set, resulting in something resembling the following:
template<std::size_t SX, std::size_t SY,
typename = std::enable_if_t<IsValidArrayXSize<SX>{} && IsValidArrayYSize<SY>{}>>
void PickyArrayHandler(std::array<int, SX> const& x, std::array<int, SY> const& y) {
// Do whatever
}
First we need to declare our valid sizes; I don't see any benefit to stronger typing here, so for a compile-time list of integers, std::integer_sequence works just fine and is very lightweight:
using SizesForArrayX = std::index_sequence<3, 4, 40>;
using SizesForArrayY = std::index_sequence<2, 3, 122>;
Now for the IsValidArraySize traits... The straightforward route is to make use of C++14's relaxed-constexpr rules and perform a simple linear search:
#include <initializer_list>
namespace detail {
template<std::size_t... VSs>
constexpr bool idx_seq_contains(std::index_sequence<VSs...>, std::size_t const s) {
for (auto const vs : {VSs...}) {
if (vs == s) {
return true;
}
}
return false;
}
} // namespace detail
template<std::size_t S>
using IsValidArrayXSize
= std::integral_constant<bool, detail::idx_seq_contains(SizesForArrayX{}, S)>;
template<std::size_t S>
using IsValidArrayYSize
= std::integral_constant<bool, detail::idx_seq_contains(SizesForArrayY{}, S)>;
Online Demo
However if compile times are at all a concern, I suspect the following will be better, if potentially less clear:
namespace detail {
template<bool... Bs>
using bool_sequence = std::integer_sequence<bool, Bs...>;
template<typename, std::size_t>
struct idx_seq_contains;
template<std::size_t... VSs, std::size_t S>
struct idx_seq_contains<std::index_sequence<VSs...>, S>
: std::integral_constant<bool, !std::is_same<bool_sequence<(VSs == S)...>,
bool_sequence<(VSs, false)...>>{}>
{ };
} // namespace detail
template<std::size_t S>
using IsValidArrayXSize = detail::idx_seq_contains<SizesForArrayX, S>;
template<std::size_t S>
using IsValidArrayYSize = detail::idx_seq_contains<SizesForArrayY, S>;
Online Demo
Whichever implementation route is chosen, using SFINAE in this way enables very nice error messages – e.g. for PickyArrayHandler(std::array<int, 5>{}, std::array<int, 3>{});, current Clang 7.0 ToT yields the following, telling you which array's size is invalid:
error: no matching function for call to 'PickyArrayHandler'
PickyArrayHandler(std::array<int, 5>{}, std::array<int, 3>{});
^~~~~~~~~~~~~~~~~
note: candidate template ignored: requirement 'IsValidArrayXSize<5UL>{}' was not satisfied [with SX = 5, SY = 3]
void PickyArrayHandler(std::array<int, SX> const& x, std::array<int, SY> const& y) {
^

c++11 constexpr flatten list of std::array into array

I am beginning with c++11, constexpr and template metaprogramming seems a nice way to save scarce ram on tiny microcontroler.
Is there a way to write a template to flatten a list of constexpr array, what
I need is a way to do :
constexpr std::array<int, 3> a1 = {1,2,3};
constexpr std::array<int, 2> a2 = {4,5};
constexpr auto a3 = make_flattened_array (a1,a2);
I use gcc 4.8.4 (arm-none-eabi), and can compile with std=c++11 or c++1y option if it is needed.
Notice - I understood your question as follows: you want to join those two arrays and flatten the result into a single, new array containing the concatenation of their elements.
You can accomplish your goal with three C++11+ concepts:
Variadic templates
constexpr expressions
Parameter pack
You start by creating a template (an empty shell) to start designing your recursive-fashion list flattening function:
template<unsigned N1, unsigned N2>
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2){
// TODO
}
so far so good: the constexpr specifier will hint the compiler to compile-time evaluate that function each time it can.
Now for the interesting part: std::array has (since c++1y) a constexpr overload for the operator[], this means you can write something like
template<unsigned N1, unsigned N2>
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2){
return std::array<int,N1+N2>{a1[0],a1[1],a1[2],a2[0],a2[1]};
}
(notice the aggregate-initialization to initialize the object from a series of integer values)
Obviously manually hard-coding all the index accesses to the values of the two arrays is no better than just declaring the concatenated array itself. The concept that will save the day is the following: Parameter Packs. A template parameter pack is a template parameter that accepts 0 or more template arguments. A template with at least one parameter pack is called variadic template.
The cool thing is the ability of expanding the parameter pack into specified locations like:
#include <iostream>
#include <array>
template<unsigned... Num>
std::array<int, 5> function(const std::array<int,5>& source) {
return std::array<int,5>{source[Num]...};
}
int main() {
std::array<int,5> source{7,8,9,10,11};
std::array<int,5> res = function<0,1,2,3,4>(source);
for(int i=0; i<res.size(); ++i)
std::cout << res[i] << " "; // 7 8 9 10 11
return 0;
}
So the only thing we need right now is to be able to compile-time generate the "index series" like
std::array<int,5> res = function<0,1,2,3,4>(source);
^ ^ ^ ^ ^
At this point we can again take advantage of the parameter packs in conjunction with an inheritance mechanism: the idea is to have a deeply nested hierarchy of derived : base : other_base : another_base : ... classes which would "accumulate" the indices into the parameter pack and terminate the "recursion" when the index reaches 0. If you didn't understand the previous sentence don't worry and take a look at the following example:
std::array<int, 3> a1{42,26,77};
// goal: having "Is" = {0,1,2} i.e. a1's valid indices
template<unsigned... Is> struct seq;
we can generate a sequence of indices in the following way:
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, Is...>{}; // each time decrement the index and go on
template<unsigned... Is>
struct gen_seq<0 /*stops the recursion*/, Is...> : /* generate the sequence */seq<Is...>{};
std::array<int, 3> a1{42,26,77};
gen_seq<3>{};
There's something missing anyway: the code above will start with gen_seq<3, (nothing)> and instantiate the specified template which will instantiate the gen_seq<2, (nothing)> as its base class that will instantiate the gen_seq<1, (nothing)> as its base class that will instantiate the gen_seq<0, (nothing)> as its base class that will instantiate the seq<(nothing)> as final sequence.
The sequence is '(nothing)', something is wrong..
In order to "accumulate" the indices into the parameter pack you need to "add a copy" of the decreased index to the parameter pack at each recursion:
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, /*This copy goes into the parameter pack*/ N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0 /*Stops the recursion*/, Is...> : /*Generate the sequence*/seq<Is...>{};
template<unsigned... Is> struct seq{};
// Using '/' to denote (nothing)
gen_seq<3,/> : gen_seq<2, 2,/> : gen_seq<1, 1,2,/> : gen_seq<0, 0,1,2,/> : seq<0,1,2,/> .
so now we're able to recollect all the pieces together and generate two sequences of indices: one for the first array and one for the second array and concatenate them together into a new return array which will hold the concatenated and flattened union of the two arrays (like appending them together).
The following code, at this point, should be easily comprehensible:
#include <iostream>
#include <array>
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
// Expansion pack
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2, seq<I1...>, seq<I2...>){
return { a1[I1]..., a2[I2]... };
}
template<unsigned N1, unsigned N2>
// Initializer for the recursion
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2){
return concat(a1, a2, gen_seq<N1>{}, gen_seq<N2>{});
}
int main() {
constexpr std::array<int, 3> a1 = {1,2,3};
constexpr std::array<int, 2> a2 = {4,5};
constexpr std::array<int,5> res = concat(a1,a2);
for(int i=0; i<res.size(); ++i)
std::cout << res[i] << " "; // 1 2 3 4 5
return 0;
}
http://ideone.com/HeLLDm
References:
https://stackoverflow.com/a/13294458/1938163
http://en.cppreference.com/
http://en.wikipedia.org
With C++1y, an implementation may (although it is not required) allow std::tuple_cat to work with any tuple-like types, and not just std::tuple<T...>. In our case, std::array<T, N> is such a type. So we could attempt:
constexpr std::array<int, 3> a1 = {1, 2, 3};
constexpr std::array<int, 2> a2 = {4, 5};
constexpr auto a3 = std::tuple_cat(a1, a2);
// note:
// not possible
// constexpr auto e = a3[3]
// instead
constexpr auto e = std::get<3>(a3);
As it so happens though, the result of a call to std::tuple_cat is a tuple, not an array. It is then possible to turn an std::tuple<T, T,… , T> into an std::array<T, N>:
template<
typename Tuple,
typename VTuple = std::remove_reference_t<Tuple>,
std::size_t... Indices
>
constexpr std::array<
std::common_type_t<std::tuple_element_t<Indices, VTuple>...>,
sizeof...(Indices)
>
to_array(Tuple&& tuple, std::index_sequence<Indices...>)
{
return { std::get<Indices>(std::forward<Tuple>(tuple))... };
}
template<typename Tuple, typename VTuple = std::remove_reference_t<Tuple>>
constexpr decltype(auto) to_array(Tuple&& tuple)
{
return to_array(
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<VTuple>::value> {} );
}
(As it turns out this to_array implementation converts any tuple-like into an array as long as the tuple element types are compatible.)
Here’s a live example for GCC 4.8, filling in some of the C++1y features not yet supported.
Luc's post answer the question.
But for fun, here is a C++14 solution without template metaprogramming, just pure constexpr.
There is a catch though, generalized constexpr was voted into the standard core language more than one year ago, but the STL still isn't updated yet...
As an experiment, open the header <array> and add an obviously missing constexpr for non-const operator[]
constexpr reference operator[](size_type n);
Also open <numeric> and turn std::accumulate into a constexpr function
template <class InputIterator, class T>
constexpr T accumulate(InputIterator first, InputIterator last, T init);
Now we can do :
#include <iostream>
#include <array>
#include <numeric>
template <typename T, size_t... sz>
constexpr auto make_flattened_array(std::array<T, sz>... ar)
{
constexpr size_t NB_ARRAY = sizeof...(ar);
T* datas[NB_ARRAY] = {&ar[0]...};
constexpr size_t lengths[NB_ARRAY] = {ar.size()...};
constexpr size_t FLATLENGTH = std::accumulate(lengths, lengths + NB_ARRAY, 0);
std::array<T, FLATLENGTH> flat_a = {0};
int index = 0;
for(int i = 0; i < NB_ARRAY; i++)
{
for(int j = 0; j < lengths[i]; j++)
{
flat_a[index] = datas[i][j];
index++;
}
}
return flat_a;
}
int main()
{
constexpr std::array<int, 3> a1 = {1,2,3};
constexpr std::array<int, 2> a2 = {4,5};
constexpr std::array<int, 4> a3 = {6,7,8,9};
constexpr auto a = make_flattened_array(a1, a2, a3);
for(int i = 0; i < a.size(); i++)
std::cout << a[i] << std::endl;
}
(Compile and run on clang trunk)
Another way is using expression templates. It does not copy arrays.
A sketch:
#include <array>
template<class L, class R>
struct AddOp
{
L const& l_;
R const& r_;
typedef typename L::value_type value_type;
AddOp operator=(AddOp const&) = delete;
constexpr value_type const& operator[](size_t idx) const {
return idx < l_.size() ? l_[idx] : r_[idx - l_.size()];
}
constexpr std::size_t size() const {
return l_.size() + r_.size();
}
// Implement the rest of std::array<> interface as needed.
};
template<class L, class R>
constexpr AddOp<L, R> make_flattened_array(L const& l, R const& r) {
return {l, r};
}
constexpr std::array<int, 3> a1 = {1,2,3};
constexpr std::array<int, 2> a2 = {4,5};
constexpr std::array<int, 2> a3 = {6};
constexpr auto a4 = make_flattened_array(a1,a2);
constexpr auto a5 = make_flattened_array(a4,a3);
int main() {
constexpr auto x = a5[1];
constexpr auto y = a5[4];
constexpr auto z = a5[5];
}

Implementing std::array-like constructors in other classes

In all the modern C++ compilers I've worked with, the following is legal:
std::array<float, 4> a = {1, 2, 3, 4};
I'm trying to make my own class that has similar construction semantics, but I'm running into an annoying problem. Consider the following attempt:
#include <array>
#include <cstddef>
template<std::size_t n>
class float_vec
{
private:
std::array<float, n> underlying_array;
public:
template<typename... Types>
float_vec(Types... args)
: underlying_array{{args...}}
{
}
};
int main()
{
float_vec<4> v = {1, 2, 3, 4}; // error here
}
When using int literals like above, the compiler complains it can't implicitly convert int to float. I think it works in the std::array example, though, because the values given are compile-time constants known to be within the domain of float. Here, on the other hand, the variadic template uses int for the parameter types and the conversion happens within the constructor's initializer list where the values aren't known at compile-time.
I don't want to do an explicit cast in the constructor since that would then allow for all numeric values even if they can't be represented by float.
The only way I can think of to get what I want is to somehow have a variable number of parameters, but of a specific type (in this case, I'd want float). I'm aware of std::initializer_list, but I'd like to be able to enforce the number of parameters at compile time as well.
Any ideas? Is what I want even possible with C++11? Anything new proposed for C++14 that will solve this?
A little trick is to use constructor inheritance. Just make your class derive from another class which has a pack of the parameters you want.
template <class T, std::size_t N, class Seq = repeat_types<N, T>>
struct _array_impl;
template <class T, std::size_t N, class... Seq>
struct _array_impl<T, N, type_sequence<Seq...>>
{
_array_impl(Seq... elements) : _data{elements...} {}
const T& operator[](std::size_t i) const { return _data[i]; }
T _data[N];
};
template <class T, std::size_t N>
struct array : _array_impl<T, N>
{
using _array_impl<T, N>::_array_impl;
};
int main() {
array<float, 4> a {1, 2, 3, 4};
for (int i = 0; i < 4; i++)
std::cout << a[i] << std::endl;
return 0;
}
Here is a sample implementation of the repeat_types utility. This sample uses logarithmic template recursion, which is a little less intuitive to implement than with linear recursion.
template <class... T>
struct type_sequence
{
static constexpr inline std::size_t size() noexcept { return sizeof...(T); }
};
template <class, class>
struct _concatenate_sequences_impl;
template <class... T, class... U>
struct _concatenate_sequences_impl<type_sequence<T...>, type_sequence<U...>>
{ using type = type_sequence<T..., U...>; };
template <class T, class U>
using concatenate_sequences = typename _concatenate_sequences_impl<T, U>::type;
template <std::size_t N, class T>
struct _repeat_sequence_impl
{ using type = concatenate_sequences<
typename _repeat_sequence_impl<N/2, T>::type,
typename _repeat_sequence_impl<N - N/2, T>::type>; };
template <class T>
struct _repeat_sequence_impl<1, T>
{ using type = T; };
template <class... T>
struct _repeat_sequence_impl<0, type_sequence<T...>>
{ using type = type_sequence<>; };
template <std::size_t N, class... T>
using repeat_types = typename _repeat_sequence_impl<N, type_sequence<T...>>::type;
First of what you are seeing is the default aggregate initialization. It has been around since the earliest K&R C. If your type is an aggregate, it supports aggregate initialization already. Also, your example will most likely compile, but the correct way to initialize it is std::array<int, 3> x ={{1, 2, 3}}; (note the double braces).
What has been added in C++11 is the initializer_list construct which requires a bit of compiler magic to be implemented.
So, what you can do now is add constructors and assignment operators that accept a value of std::initializer_list and this will offer the same syntax for your type.
Example:
#include <initializer_list>
struct X {
X(std::initializer_list<int>) {
// do stuff
}
};
int main()
{
X x = {1, 2, 3};
return 0;
}
Why does your current approach not work? Because in C++11 std::initializer_list::size is not a constexpr or part of the initializer_list type. You cannot use it as a template parameter.
A few possible hacks: make your type an aggregate.
#include <array>
template<std::size_t N>
struct X {
std::array<int, N> x;
};
int main()
{
X<3> x = {{{1, 2, 3}}}; // triple braces required
return 0;
}
Provide a make_* function to deduce the number of arguments:
#include <array>
template<std::size_t N>
struct X {
std::array<int, N> x;
};
template<typename... T>
auto make_X(T... args) -> X<sizeof...(T)>
// might want to find the common_type of the argument pack as well
{ return X<sizeof...(T)>{{{args...}}}; }
int main()
{
auto x = make_X(1, 2, 3);
return 0;
}
If you use several braces to initialize the instance, you can leverage list-init of another type to accept these conversions for compile-time constants. Here's a version that uses a raw array, so you only need parens + braces for construction:
#include <array>
#include <cstddef>
template<int... Is> struct seq {};
template<int N, int... Is> struct gen_seq : gen_seq<N-1, N-1, Is...> {};
template<int... Is> struct gen_seq<0, Is...> : seq<Is...> {};
template<std::size_t n>
class float_vec
{
private:
std::array<float, n> underlying_array;
template<int... Is>
constexpr float_vec(float const(&arr)[n], seq<Is...>)
: underlying_array{{arr[Is]...}}
{}
public:
constexpr float_vec(float const(&arr)[n])
: float_vec(arr, gen_seq<n>{})
{}
};
int main()
{
float_vec<4> v0 ({1, 2, 3, 4}); // fine
float_vec<4> v1 {{1, 2, 3, 4}}; // fine
float_vec<4> v2 = {{1, 2, 3, 4}}; // fine
}
Explicitly specify that the data type for the initialization to floating point type. You can do this by doing "1.0f" instead of putting "1". If it is a double, put "1.0d". If it is a long, put "1l" and for unsigned long put "1ul" and so on..
I've tested it here: http://coliru.stacked-crooked.com/a/396f5d418cbd3f14
and here: http://ideone.com/ZLiMhg
Your code was fine. You just initialized the class a bit incorrect.
#include <array>
#include <cstddef>
#include <iostream>
template<std::size_t n>
class float_vec
{
private:
std::array<float, n> underlying_array;
public:
template<typename... Types>
float_vec(Types... args)
: underlying_array{{args...}}
{
}
float get(int index) {return underlying_array[index];}
};
int main()
{
float_vec<4> v = {1.5f, 2.0f, 3.0f, 4.5f}; //works fine now..
for (int i = 0; i < 4; ++i)
std::cout<<v.get(i)<<" ";
}

C++11 return a std::array with different sizes

I'd like to create such a structure:
struct Arrays{
typedef unsigned char byte_t;
std::array<byte_t, X>& get(int x, int y)
{
switch(x){
case 1: return arr_1.at(y);
case 2: return arr_2.at(y);
... up to ...
case 50: return arr_50.at(y);
default: break;
}
}
std::vector<std::array<byte_t, 1>> arr_1;
std::vector<std::array<byte_t, 2>> arr_2;
... up to ....
std::vector<std::array<byte_t, 50>> arr_50;
};
I know that
std::array<byte_t, 1>
and
std::array<byte_t, 2>
are different structures, so this is impossible in this way. How can I managed with it in different manner? Do I have to return byte_t* from the method?
As the previous comments have said, the array size is a compile-time constant. The only way to achieve this then is to pass x as a template argument. How about the following? (For convenience, I have defined a class vector_of_arrays to hold your vectors arr_1 to arr_50 in such a way that I can refer to each one by the number rather than having to switch and give a name)
#include <array>
#include <type_traits>
#include <vector>
template <typename type, size_t max_size>
class vector_of_arrays : public std::vector<std::array<type, max_size>>
{
private:
vector_of_arrays<type, max_size - 1> _next;
public:
template <size_t size>
typename std::enable_if<(size < max_size), vector_of_arrays<type, size>&>::type
get_vector_for_size()
{
return _next.get_vector_for_size<size>();
}
template <size_t size>
typename std::enable_if<(size == max_size), vector_of_arrays<type, size>&>::type
get_vector_for_size()
{
return *this;
}
};
template <typename type>
class vector_of_arrays<type, 1> : public std::vector<std::array<type, 1>>
{
public:
template <size_t size>
typename std::enable_if<(size == 1), vector_of_arrays<type, size>&>::type
get_vector_for_size()
{
return *this;
}
};
struct arrays
{
typedef unsigned char byte_t;
vector_of_arrays<byte_t, 50> va;
template <size_t x>
std::array<byte_t, x>& emplace_array()
{
va.get_vector_for_size<x>().emplace_back();
return *(va.get_vector_for_size<x>().end() - 1);
}
template <size_t x>
std::array<byte_t, x>& get(int y)
{
return va.get_vector_for_size<x>().at(y);
}
};
To test this code, you could do something like
arrays foo;
auto& arr1 = foo.emplace_array<3>();
arr1[0] = 1.;
arr1[1] = 2.;
arr1[2] = 3.;
auto& arr2 = foo.get<3>(0);
std::cout << arr2[0] << ' ' << arr2[1] << ' ' << arr2[2] << std::endl;
First, you are violating DRY.
Replace this:
std::vector<std::array<byte_t, 1>> arr_1;
std::vector<std::array<byte_t, 2>> arr_2;
... up to ....
std::vector<std::array<byte_t, 50>> arr_50;
with something like:
template<typename Pack, unsigned X> struct append;
template<template<unsigned...>class Pack, unsigned... Xs, unsigned X>
struct append<Pack<Xs...>, X> {
typedef Pack<Xs..., X> type;
};
template<typename Pack, unsigned X> using Append=typename append<Pack,X>::type;
template<unsigned N, template<unsigned>class Contents>
struct auto_tuple {
typedef Append< typename auto_tuple<N-1, Contents>::type, Contents<N-1> > type;
};
template<template<unsigned>class Contents>
struct auto_tuple<0, Contents> {
typedef std::tuple<> type;
};
template<unsigned N, template<unsigned>class Contents>
using AutoTuple = typename auto_tuple<N,Contents>::type;
where AutoTuple<N, Contents> applies 0 through N-1 to Contents and generates a std::tuple out of it. Write:
template<typename T, unsigned N>
using vec_of_array = std::vector<std::array<T, N>>;
template<unsigned N>
using vec_of_byte_array = vec_of_array<byte_t, N>;
template<unsigned N>
using get_nth_byte_array = vec_of_byte_array<N+1>;
which you use to populate your tuple like:
typedef AutoTuple<50, get_nth_byte_array> my_tuple;
which is a std::tuple of 50 different std::vectors, each of which store a std::array of 1 through 50 bytes.
This took far fewer than 50 lines, and while this will be harder to get it to work and understand it, it means that the code is uniform and generated once: there is far less of a chance that one particular line is wrong, and a far higher chance that everything is wrong at once. And you can use a compile-time value to extract the nth element via std::get<7>(my_tuple). Oh, and if you want 100 or 10 instead of 50? Change one constant.
Next, a contiguous_range structure that is basically a dressed up pair of pointers gives you a type-erased way to look at an array (or other buffer) of N elements, like Passing a std::array of unknown size to a function
Now, you can either write your big switch statement manually, or you can build a table of function pointers that extract the contiguous_range and build it automatically.
// DataStorage is the tuple of std::vector of std::array
template<unsigned...> struct seq{};
template<unsigned max, unsigned... s> struct make_seq:make_seq<max-1, max-1, s...> {};
template<unsigned... s> struct make_seq<0,s...>:seq<s...> {};
template<unsigned N>
struct get_array {
static contig_range<byte> get(DataStorage& data, unsinged idx) {
return ( std::get<N>( std::forward<Data>(data) )[idx];
}
};
and build an array of 50 of them (each with a different N) stored in an array of:
typedef contig_range<byte> (*array_getter)( DataStorage&, unsigned idx );
template<unsigned N, unsigned... S>
std::array< array_getter, N > populate_array_helper( seq<S...> ) {
return { get_array<S>::get... };
}
template<unsigned N>
std::array< array_getter, N > populate_array() {
return populate_array_helper( make_seq<N>() );
}
which you can then use the run-time argument to lookup, call it, and you get a type-erased instance of your contiguous array of byte.
Non-code overhead is 50 pointers (for the lookup table), 3 pointers (for the containing vector).
And you never do a cpoy/paste of the same code 50 times over with a single number changed each time, one of which has a slight typo in it that generates a subtle fenceposting bug that only occurs in one obscure, hard to reproduce test case in release mode only.