integer increment inside pack expansion - c++

I have two functions row and col. row is a wrapper for col and should pack the return types to a tuple.
Something like this
#include <iostream>
#include <tuple>
template<typename T>
T col(size_t i)
{
return T(i);
}
template<typename ...Ts>
auto row()
{
size_t i = 0;
return std::make_tuple(col<Ts>(i++)...); //<-- undefined behaviour
}
int main()
{
auto m_row = row<int,int,double>(); //should expand to std::make_tuple(col<int>(0),col<int>(1),col<double(2));
std::cout << "std::get<0>(m_row)-" << std::get<0>(m_row) << std::endl;
std::cout << "std::get<1>(m_row)-" << std::get<1>(m_row) << std::endl;
std::cout << "std::get<2>(m_row)-" << std::get<2>(m_row) << std::endl;
return 0;
}
My problem is the integer i which has to be incremented inside the expansion from 0 up to sizeof...(Ts). I have considered index of the current type but this is not working if the types are not unique. I lack of other ideas, any help would be appreciated.

Using std::index_sequence_for we can achieve a moderately simple (but not as simple as I had hoped) solution.
As #NathanOliver mentioned, it requires a level of indirection because we need to inform a helper function of the index sequence. The top level function now looks like this:
template <typename... Ts>
auto row() {
return make_row(std::tuple<Ts...>{},
std::index_sequence_for<Ts...>{});
}
So the helper function takes a default constructed tuple of the type requested, and the compile time sequence of integers.
All the helper needs to do now is to construct a Tuple using the index sequence (0, 1, ...).
template <typename Tuple, std::size_t... Is>
auto make_row(Tuple, std::index_sequence<Is...>) {
return Tuple{ Is... };
}
Finally, to verify this does what we wanted:
int main()
{
auto r = row<int,int,double>();
static_assert(std::is_same<decltype(r), std::tuple<int, int, double>>::value);
}

Related

How to expand the parameter package without recursion and not decomposing the elements into an array?

#include <iostream>
using namespace std;
template <class T, class... Other>
auto sum(T& first, Other... other)
{
T mas[] = { other... };
cout << "size: " << sizeof...(other) << endl;
//T *f = other...;
for (int m : mas)
first += m;
return first;
}
int main()
{
int summa = 0;
sum(summa, 1, 2, 3, 4, 5, 6, 7);
cout << "sum: " << summa << endl;
return 0;
}
There is a short piece of code that outputs the following:
size: 7
sum: 28
The question is very simple and quick to get the same answer:
How do I access element by element each variable accounting parameter other? I tried to create a pointer, but it constantly complains, in short, I don’t know how it looks syntactically.
I will make a reservation right away that I am not interested in how to decompose the elements into an array, I myself know how exactly I should refer to each element exactly other.
More precisely, how to expand the parameter package without recursion and not decomposing the elements into an array?
How to expand the parameter package without recursion?
You have since C++17-fold expression for this needs.
Using it, your function will simply be
template <class T, class... Other>
auto sum(T& first, const Other&... other)
{
first = (other + ... + first);
return first;
}
or without the redundant variable summa may be:
#include <type_traits> // std::common_type_t
template <class... Other>
constexpr auto sum(const Other&... other) /* noexcept */
{
return (other + ... + std::common_type_t<Other...>{});
}
See a demo
How do I access element by element each variable accounting parameter other?
You can apply fold expression along with an immediately invoking lambda function as follows:
template <typename ReType, typename... Other>
auto do_something_with_args(ReType& ret, Other&&... other)
{
([&ret](auto /* const& */ arg) {
// do something with each arg and ret
ret += arg; // example
std::cout << arg << '\n';
}(std::forward<Other>(other)), ...);
return ret;
}
See a demo
If you do not have access to C++17, then there are tweaks/ alternatives, which have been mentioned in the following posts:
What is a good alternative to this C++17 fold expression in C++14?
How to call a function on all variadic template args?
How about this solution?
template <class T, class... Other>
auto sum(T& first, Other... other)
{
std::apply([&first](auto &&... i){(..., (first += i)); }, std::make_tuple(std::forward<Other>(other)...));
return first;
}

Generate const array of pointers to callback functions

I'd like to generate an array of N pointers to callbacks so I don't have to type them explicitly (LOC is not the issue here).
I use C++17.
Here is what I have:
using Callback = void(*)();
auto constexpr N = 2;
const Callback callbacks[N] = {
[](){ auto i = 0; std::cout<<"callback " << i << "\n";},
[](){ auto i = 1; std::cout<<"callback " << i << "\n";}
};
callbacks[0]();
callbacks[N-1]();
Here is what I want:
const auto callbacks = generate_callbacks<N>(); // or generate_callbacks(N)
callbacks[i](); // cout<<"callback " << i << "\n";
I tried various ways, but I keep running into the problems with constant parameters even when they are from a constexpr function or variadic template.
If I try this:
Callback callbacks[N] = { };
for(int i=0;i<N;++i)
{
callbacks[i] = [i](){ std::cout<<"callback " << i << "\n";};
}
for(int i=0;i<N;++i)
{
callbacks[i]();
}
I get the following error:
main.cpp:91:66: error: cannot convert ‘main()::’ to ‘Callback {aka void (*)()}’ in assignment
callbacks[i] = [i](){ std::cout<<"callback " << i << "\n";};
If I make i static and leave out the capture it only uses the last value of i:
callback 2
callback 2
This is odd to me as capturing should be done at construction. Are the lambdas constructed after the loop exits?
As for the purpose. I want to apply this technique to generating interrupt handlers for microcontrollers. I can put the function pointers in the interrupt vector table directly. These functions have no parameters and I don't know a clean way to detect which interrupt source called the handler. I can write a handler for each interrupt, but I don't like repeating this code 6 times:
void handler0()
{
do_something(0);
}
Typing it as a lambda and/or using a template makes it a little cleaner, but I still have to type something N times. And if N changes I have to change multiple lines of code. This is not elegant.
Off Topic Suggestion: don't use, when you can, C-styles arrays but C++ std::array.
For example: the following line
const auto callbacks = generate_callbacks<N>();
can't works if you want that callbacks is a C-style array (a function can't return that type) but works when generate_callback() return a std::array<Callback, N> instance.
End of Off Topic Suggestion.
In this particular case, given that N is a constexpr value, I propose the use of template meta-programming.
So I suggest the following generate_callbacks() function, that just create a sequence of template values from zero to N-1 and call an helper function
template <std::size_t N>
auto generate_callbacks ()
{ return gc_helper(std::make_index_sequence<N>{}); }
and a simple helper function that uses the template values and create the callbacks lambdas without capturing them (so remaining convertible to function pointers)
template <std::size_t ... Is>
std::array<Callback, sizeof...(Is)> gc_helper (std::index_sequence<Is...>)
{ return {{ []{ auto i = Is; std::cout<<"callback " << i << "\n"; }... }}; }
If you can use C++20, using template lambdas you can avoid the external gc_helper() function and make all inside generate_callbacks() as follows
template <std::size_t N>
auto generate_callbacks ()
{
return []<std::size_t ... Is>(std::index_sequence<Is...>)
-> std::array<Callback, N>
{ return {{ []{ std::cout<<"callback " << Is << "\n"; }... }}; }
(std::make_index_sequence<N>{});
}
The following is a full compiling C++17 C++14 example
#include <iostream>
#include <utility>
#include <array>
using Callback = void(*)();
auto constexpr N = 2;
template <std::size_t ... Is>
std::array<Callback, sizeof...(Is)> gc_helper (std::index_sequence<Is...>)
{ return {{ []{ auto i = Is; std::cout<<"callback " << i << "\n"; }... }}; }
template <std::size_t N>
auto generate_callbacks ()
{ return gc_helper(std::make_index_sequence<N>{}); }
int main()
{
const auto callbacks = generate_callbacks<N>();
for ( auto ui = 0 ; ui < N ; ++ui )
callbacks[ui]();
}
The following compiles fine in both gcc and clang in C++17 mode. It uses some simple template metaprogramming to generate the sequence of callbacks.
#include <array>
#include <iostream>
using cb = void (*)();
template<int N>
inline auto fun()
{
std::cout << "callback: " << N << '\n';
}
template<int N>
void init(cb * arr)
{
arr[N] = &fun<N>;
init<N-1>(arr);
}
template<>
void init<0>(cb * arr)
{
arr[0] = &fun<0>;
}
template<int N>
struct callbacks
{
callbacks()
{
init<N>(cbs.data());
}
std::array<cb, N> cbs;
};
int main()
{
auto foo = callbacks<4>();
for (auto x = 0; x < 4; ++x)
{
foo.cbs[x]();
}
}

Is there a way to use std::get(std::tuple) with a non-const int as template argument?

I'm trying to figure out how to loop through the members of an std::tuple, but it seems that I can only ever use constexpr ints or const ints in the std::get template argument. I've looked around and I saw some solutions or ideas using recursive functions or structs, but I don't really understand them. I'd very much appreciate help with this (my code is below).
#include <tuple>
#include <iostream>
int main() {
std::tuple<int, int> tuple(3, 4);
for (int i = 0; i < 2; i++)
std::cout << std::get<i>(tuple) << std::endl;
}
And here is the error:
main.cpp: In function ‘int main()’:
main.cpp:8:31: error: the value of ‘i’ is not usable in a constant expression
std::cout << std::get<i>(tuple) << std::endl;
^
Is there a way to use std::get(std::tuple) with a non-const int as template argument?
No, there isn't. Template arguments are always compile time constants.
Besides, return types are also set in stone at compile time, and given that tuple elements can be of different types, the compiler couldn't know what type to return which would be a problem.
Now, even though you cannot have std::get with a runtime parameter, there are ways to iterate the elements. std::apply from the standard library will call a provided function with the tuple elements as arguments. You can use a variadic template arguments to accept any tuple, and expand the arguments with a fold expression.
auto visitor = [](auto&&... args) {
((std::cout << args << '\n'), ...);
};
std::apply(visitor, tuple);
The problem is that if the compiler doesn't know which index is going to be accessed, it can't (in general) know which type to return from the tuple. So the trick is to not return anything. Usually, to use a helper function that uses a switch statement to decide which type to use, and pass the function to that.
I don't have a compiler handy, but that would look something vaguely like this:
template<class Func, class... Args>
auto apply_indexed(Func&& func, std::tuple<Args...>& tuple, int index)
-> decltype(func(std::get<0>(tuple)))
{
switch(index) {
case 0: return func(std::get<0>(tuple);
case 1: return func(std::get<1>(tuple);
}
throw std::invalid_argument("illegal index to invoke_tuple " + std::to_string(index));
}
int main() {
std::tuple<int, int> tuple(3, 4);
for (int i = 0; i < 2; i++)
apply_indexed([](auto& element){
std::cout << element << std::endl;
}, tuple, index);
}
This creates an anonymous lambda that can accept any of the tuple types, and then uses a switch statement to decide which element to pass in.
The problem you've got is that std::get expects a compile time value whereas your variable i is only known at run time. You can do this:
std::tuple<int, int> tuple(3, 4);
std::cout << std::get<0>(tuple) << std::endl;
std::cout << std::get<1>(tuple) << std::endl;
but it will only work for a two-element tuple. However, there is a way using a variadic template function that will allow to use a tuple of any size. You will need an index list to get elements within a tuple. In C++14 onward you've got std::integer_sequence, which can be created using std::index_sequence_for. std::integer_sequence represents a compile-time sequence of integers, and when used as an argument to a function template the parameter pack of type std::size_t can be deduced and used in pack expansion.
This will do want to want in C++14 onwards:
#include <tuple>
#include <iostream>
template<typename Tuple, std::size_t... Is>
void print_tuple_impl(Tuple& t, std::index_sequence<Is...>)
{
using unused = int[];
//print each tuple element using index sequence
(void)unused { 0, ((std::cout << std::get<Is>(t) << std::endl), 0) ... };
}
template<typename... Args>
void print_tuple(std::tuple<Args...> tup)
{
//create index sequence and pass to print_tuple_impl
print_tuple_impl(tup, std::index_sequence_for<Args...>{});
}
int main()
{
std::tuple<int, int> tuple(3, 4);
print_tuple(tuple);
}
Here's a demo.
In C++17, you can use a fold expression without creating a temporary array for pack expansion:
((std::cout << std::get<Is>(t) << std::endl), ...);
Demo

Default constructing an std::variant from index

What's the easiest way to default construct an std::variant from the index of the desired type, when the index is only known at runtime? In other words, I want to write:
const auto indx = std::variant<types...>{someobject}.index();
//...somewhere later, indx having been passed around...
std::variant<types...> var = variant_from_index(indx);
///var is now set to contain a default constructed someobject
Note that indx cannot be made constexpr, so std::in_place_index doesn't work here.
The problem here is of course that since it isn't known which constructor from types... to call at compile time, somehow basically a table of all possible constructors (or maybe default constructed variants to copy from) has to be built at compile time and then accessed at run time. Some template magic is apparently in place here, but what would be the cleanest way?
I tried the following (on coliru), but the index sequence seems to come out wrong (the print in the end gives 2 0 0), and I'm confused as to why:
Edit: it works as fixed below, I had the constexpr array initialization wrong. So the question is now, is there a neater way to do this?
#include <variant>
#include <iostream>
using var_t = std::variant<int, float, const char *>;
//For debug
template<class ...types>
struct WhichType;
template<class T, class U>
struct default_variants;
template<class...Params, std::size_t... I>
struct default_variants<std::variant<Params...>, std::index_sequence<I...>> {
using variant_t = std::variant<Params...>;
//Uncomment to see the index sequence
//WhichType<std::index_sequence<I...>> idx{};
constexpr static variant_t variants[sizeof...(Params)]{variant_t{std::in_place_index<I>}...};
constexpr static std::size_t indices[sizeof...(Params)]{I...};
};
template<class T>
struct default_variants_builder;
template<class...Params>
struct default_variants_builder<std::variant<Params...>> {
using indices = std::make_index_sequence<sizeof...(Params)>;
using type = default_variants<std::variant<Params...>, indices>;
};
int main() {
using builder_t = typename default_variants_builder<var_t>::type;
var_t floatvar{1.2f};
var_t variant2 = builder_t::variants[floatvar.index()];
std::cout << "Contained " << floatvar.index() << "; Now contains " << variant2.index() << "\n";
}
With Boost.Mp11 this is basically a one-liner (as always):
template <typename V>
auto variant_from_index(size_t index) -> V
{
return mp_with_index<mp_size<V>>(index,
[](auto I){ return V(std::in_place_index<I>); });
}
Your description of the problem is accurate - you need a way to turn a runtime index into a compile-time index. mp_with_index does that for you - you give it the runtime index and the maximum compile-time index (mp_size<V> here, which would give the same value as std::variant_size_v<V> if you prefer that instead) and it will invoke a function you provide with the correct constant (I has type integral_constant<size_t, index> here, except with index being a constant expression).
How about this?
template <class Variant, std::size_t I = 0>
Variant variant_from_index(std::size_t index) {
if constexpr(I >= std::variant_size_v<Variant>)
throw std::runtime_error{"Variant index " + std::to_string(I + index) + " out of bounds"};
else
return index == 0
? Variant{std::in_place_index<I>}
: variant_from_index<Variant, I + 1>(index - 1);
}
See it live on Wandbox
Not sure if this is very elegant or not but I think it works:
#include <variant>
#include <iostream>
template<typename V, std::size_t N = std::variant_size_v<V>>
struct variant_by_index {
V make_default(std::size_t i) {
if (i >= std::variant_size_v<V>) {
throw std::invalid_argument("bad type index.");
}
constexpr size_t index = std::variant_size_v<V> - N;
if (i == index) {
return std::variant_alternative_t<index, V>();
} else {
return variant_by_index<V, N - 1>().make_default(i);
}
}
};
template<typename V>
struct variant_by_index<V, 0> {
V make_default(std::size_t i) {
throw std::bad_variant_access("bad type index.");
}
};
using var_t = std::variant<int, float, const char *>;
int main() {
variant_by_index<var_t> type_indexer;
var_t my_var_0 = type_indexer.make_default(0);
std::cout << "my_var_0 has int? " << std::holds_alternative<int>(my_var_0) << "\n";
var_t my_var_1 = type_indexer.make_default(1);
std::cout << "my_var_1 has float? " << std::holds_alternative<float>(my_var_1) << "\n";
try {
var_t my_var_1 = type_indexer.make_default(3);
} catch(const std::bad_variant_access&) {
std::cout << "Could not create with type 3.\n";
}
return 0;
}
I believe a (somewhat) elegant way might be using a more general idiom for choosing a numeric template parameter value at run time, as discussed in this question:
Idiom for simulating run-time numeric template parameters?
The foo function there will be std::get<std::size_t I> (or a lambda which captures the variant and takes no arguments).

Variadic templates. Some issues

template <class... T_values>
class Thing {
public:
void something(T_values... values) {
tuple_ = std::tuple<T_values...>(values...);
}
void do_something_with_values() {
call_yadda_with_tuple(tuple_,
std::index_sequence_for<T_value...>())
}
void yadda(T... values);
private:
//The helper method.
template<std::size_t... Is>
void call_yadda_with_tuple(const std::tuple<T_values...>& tuple,
std::index_sequence<Is...>) {
yadda(std::get<Is>(tuple)...);
}
std::tuple<T_values...> tuple_;
};
Above sourcecode comes from: https://www.murrayc.com/permalink/2015/12/05/modern-c-variadic-template-parameters-and-tuples/
I would like to ask some questions:
What does return std::index_sequence_for<T_value...>()) ?
Why in yadda(std::get<Is>(tuple)...); there is Is instead of Is...? Therefore, what does it mean Is? Is... in unpacked ( expanded ) types pack but what is Is.
Especially, which std::get fits from (1)-(8)
(http://en.cppreference.com/w/cpp/utility/tuple/get)
Why call_yadda_with_tuple gets std::index_sequence<Is...>.
After all, this argument is nameless so it is useless. I suppose that it is connected with deduction types but I cannot see how does it help?
What does return std::index_sequence_for()) ?
assuming T_value... is T, T, T (i.e. 3 types...)
std::index_sequence<0, 1, 2>
Why in yadda(std::get(tuple)...); there is Is instead of Is...? Therefore, what does it mean Is? Is... in unpacked ( expanded ) types pack but what is Is.
Is represents 'the current value of Is' while Is... is being unpacked. The trailing ... causes unpacking of the expression in which Is is used.
Especially, which std::get fits from (1)-(8) (http://en.cppreference.com/w/cpp/utility/tuple/get)
In this case the tuple reference is a const std::tuple<T_values...>& so it'll be number 3.
Why call_yadda_with_tuple gets std::index_sequence. After all, this argument is nameless so it is useless. I suppose that it is connected with deduction types but I cannot see how does it help?
It's there simply to cause Is... to exist and therefore allow you to expand across all Is in the sequence.
edit:
Here's an example with comments that hopefully explain what's going on
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
// for any value I, write a comma and space to stdout
// (i.e. ignore the value I)
template<std::size_t I>
void emit_sep()
{
std::cout << ", ";
}
// specialise for when I is zero... no comma in this case
template<>
void emit_sep<0>()
{
}
// emit and value at some position I. Use emit_sep<I> to determine whether
// to print a separator
template<std::size_t I, class T>
void emit(const T& t)
{
emit_sep<I>();
std::cout << t;
}
// given a tuple type and a sequence of integers (Is...) emit the value
// at each index position of the tuple. Take care to emit a separator only
// before each element after the first one
template<class Tuple, size_t...Is>
void impl_show_it(const Tuple& tup, std::index_sequence<Is...>)
{
using expand = int[];
std::cout << "here are the indexes in the index_sequence: ";
// the following line will expand (in our example) to:
// void(int[] { 0,
// (emit<0>(0), 0),
// (emit<1>(1), 0),
// (emit<2>(2), 0),
// });
// and the optimiser will remove the operations which have no observable
// side-effects (namely, building an array of ints which is never used)
// so the code emitted will be equivalent to:
// emit<0>(0); emit<1>(1); emit<2>(2);
//
void(expand {
0,
(emit<Is>(Is), 0)...
});
std::cout << std::endl;
std::cout << "here are the values in the tuple: ";
void(expand {
0,
(emit<Is>(std::get<Is>(tup)), 0)...
});
std::cout << std::endl;
}
// for some tuple type, compute the size of the tuple, build an index sequence
// representing each INDEX in the tuple and then use that sequence to call
// impl_show_it in order to actually perform the write
template<class Tuple>
void show_it(const Tuple& tup)
{
constexpr auto tuple_size = std::tuple_size<Tuple>::value;
auto sequence = std::make_index_sequence<tuple_size>();
impl_show_it(tup, sequence);
}
// make a tuple and then show it on stdout
int main()
{
auto t = std::make_tuple(6, std::string("hello"), 5.5);
show_it(t);
}
expected results:
here are the indexes in the index_sequence: 0, 1, 2
here are the values in the tuple: 6, hello, 5.5