Enumerating boolean template parameters in C++11 - c++

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>>{}, "!" );
}

Related

How to declare std::array when element type has no default constructor? [duplicate]

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)

Define tuple recursively

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>{}); }

Getting the number of arguments to a function at compile-time using variadic templates with argument type check in c++

Say I have a class:
template<typename... Types>
class Example
{
public:
using types = std::tuple<Types...>;
template<size_t N> using dim_type = std::tuple_element_t<N, types>;
};
And I want to implement a member function that depends on the tuple element as follows, with the goal of having access to the number of arguments during compilation:
template<size_t N>
inline constexpr void do_stuff(const dim_type<N>& elems...)
{
constexpr size_t size_stuff = sizeof...(elems); // <-- this is the end goal
};
Problem is that this implementation of do_stuff() won't do. And ultimately I would like the function to work like this:
Example<long,std::string> ex;
ex.do_stuff<0>(3);
ex.do_stuff<0>(5,6);
ex.do_stuff<1>("a","b","c","d");
ex.do_stuff<0>("a","b","c","d"); // <-- this line should not compile
ex.do_stuff<1>(1,"b"); // <-- nor should this one
And inside do_stuff I should know at compile-time how many arguments are passed.
One possible answer, but I'm having an issue with it:
I figured that a proper implementation of this would require the use of variadic templates, however, I am having a problem getting the std::enable_if part to work:
template<size_t N, typename... Args,
std::enable_if_t<static_and<std::is_convertible_v<Args, dim_type<N>>...>::value>* = nullptr>
inline constexpr void do_stuff(const Args&... elems)
{
constexpr size_t size_stuff = sizeof...(elems); // <-- this is the end goal
};
where static_and is:
template<bool Head, bool... Tail>
struct static_and {
static constexpr bool value = Head && static_and<Tail...>::value;
};
template<bool Bool> struct static_and<Bool> {
static constexpr bool value = Bool;
};
It seems to me that the right way (a possible right way) is the one based on static_and: a variadic type list Args of argument that is SFINAE checked to be convertible to the right type.
I propose the following version of static_and
template <bool ...>
struct static_and : public std::false_type
{ };
template <>
struct static_and<> : public std::true_type
{ };
template <bool ... Bs>
struct static_and<true, Bs...> : public static_and<Bs...>
{ };
and do_stuff() become
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<
static_and<std::is_convertible<Ts, type_n<I>>::value...>::value>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}
The following is a full compiling example (with compilation errors when appropriate)
#include <tuple>
#include <iostream>
#include <type_traits>
template <bool ...>
struct static_and : public std::false_type
{ };
template <>
struct static_and<> : public std::true_type
{ };
template <bool ... Bs>
struct static_and<true, Bs...> : public static_and<Bs...>
{ };
template <typename ... Types>
struct foo
{
using types = std::tuple<Types...>;
static constexpr std::size_t num_types { sizeof...(Types) };
template <std::size_t I>
using type_n = std::tuple_element_t<I, types>;
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<
static_and<std::is_convertible<Ts, type_n<I>>::value...>::value>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}
};
int main ()
{
foo<long, std::string> ex;
ex.do_stuff<0>(3); // compile; print 1
ex.do_stuff<0>(5, 6); // compile; print 2
ex.do_stuff<1>("a", "b", "c", "d"); // compile; print 4
// ex.do_stuff<0>("a", "b", "c", "d"); // compilation error
// ex.do_stuff<1>(1, "b"); // compilation error
}
If you can use C++17, instead of static_and you can simply use template folding
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<(... && std::is_convertible<Ts, type_n<I>>::value)>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}
If, in C++14, you prefer a constexpr static_and() function instead of a struct, you can write it as follows
template <bool ... Bs>
constexpr bool static_and ()
{
using unused = bool[];
bool ret { true };
(void) unused { true, ret &= Bs... };
return ret;
}
So do_stuff() become
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<
static_and<std::is_convertible<Ts, type_n<I>>::value...>()>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}

C++ constexpr : Compute a std array at compile time

I want to convert an "array" of bool to a integer sequence.
So I need to compute an std::array at compile time.
Here is my code
#include <array>
template<typename InputIt, typename T >
inline constexpr typename std::iterator_traits<InputIt>::difference_type
count( InputIt first, InputIt last, const T &value ) {
typename std::iterator_traits<InputIt>::difference_type ret = 0;
for (; first != last; ++first) {
if (*first == value) {
ret++;
}
}
return ret;
}
template<bool ..._values>
struct keep_value {
static constexpr std::size_t numberOfValues = sizeof...(_values);
static constexpr bool values[] = {_values...};
static constexpr std::size_t numberToKeep = count(values, values + numberOfValues, true);
static constexpr std::array<std::size_t, numberToKeep> computeIndices() {
std::array<std::size_t, numberToKeep> array{};
auto it = array.begin();
for(std::size_t i{0}; i < numberOfValues; ++i)
if(values[i] == true)
*it++ = i;
return array;
}
static constexpr std::array<std::size_t, numberToKeep> indices = computeIndices();
template<typename Indices = std::make_index_sequence<numberToKeep>>
struct as_index_sequence{};
template<std::size_t ...Is>
struct as_index_sequence<std::index_sequence<Is...>> : std::index_sequence<indices[Is]...>{};
};
int main() {
keep_value<false, true, true>::template as_index_sequence<>{}; // Should return the sequence 1 2
}
I get an error for the line that call the computeIndices function. Is this code c++14 correct? Is it possible to do otherwise?
I am using MSVC and I get this error :
expression did not evaluate to a constant
This code looks correct and works when compiled as C++17.
It uses std::array::begin, which only has been made constexpr in C++17.
A better compilation error can be achieved when using clang, which states:
<source>:23:25: note: non-constexpr function 'begin' cannot be used in a constant expression
auto it = array.begin();
Is it possible to do otherwise?
About correctness answered JVApen (+1).
A possible alternative is avoid std::array at all and construct the index sequence in a recursive way using template specialization
The following is a full compilable example
#include <utility>
#include <type_traits>
template <typename, std::size_t, bool...>
struct bar;
// true case
template <std::size_t ... Is, std::size_t I, bool ... Bs>
struct bar<std::index_sequence<Is...>, I, true, Bs...>
: public bar<std::index_sequence<Is..., I>, I+1U, Bs...>
{ };
// false case
template <std::size_t ... Is, std::size_t I, bool ... Bs>
struct bar<std::index_sequence<Is...>, I, false, Bs...>
: public bar<std::index_sequence<Is...>, I+1U, Bs...>
{ };
// end case
template <typename T, std::size_t I>
struct bar<T, I>
{ using type = T; };
template <bool ... Bs>
struct foo : public bar<std::index_sequence<>, 0U, Bs...>
{ };
int main()
{
static_assert( std::is_same<typename foo<false, true, true>::type,
std::index_sequence<1U, 2U>>{}, "!" );
}
If you don't like the recursive solutions, I propose (just for fun) another solution based of std::tuple_cat
#include <tuple>
#include <utility>
#include <type_traits>
template <std::size_t, bool>
struct baz
{ using type = std::tuple<>; };
template <std::size_t I>
struct baz<I, true>
{ using type = std::tuple<std::integral_constant<std::size_t, I>>; };
template <std::size_t I, bool B>
using baz_t = typename baz<I, B>::type;
template <typename, bool...>
struct bar;
template <std::size_t ... Is, bool ... Bs>
struct bar<std::index_sequence<Is...>, Bs...>
{
template <std::size_t ... Js>
constexpr static std::index_sequence<Js...>
func (std::tuple<std::integral_constant<std::size_t, Js>...> const &);
using type = decltype(func(std::tuple_cat(baz_t<Is, Bs>{}...)));
};
template <bool ... Bs>
struct foo : public bar<std::make_index_sequence<sizeof...(Bs)>, Bs...>
{ };
int main()
{
static_assert( std::is_same<typename foo<false, true, true>::type,
std::index_sequence<1U, 2U>>{}, "!" );
}

C++ parameter pack with single type enforced in arguments

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{})