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]();
}
}
Related
I would like to improve the code so that it is convenient to interact with it.
struct prototype {
template <class... T1>
prototype(T1&&... args) {
auto p = std::tie(args...);
std::cout << std::get<0>(p) << std::endl;
if constexpr(std::tuple_size_v<decltype(p)> >= 3) {
std::cout << std::get<2>(p) << std::endl;
}
}
};
int option_1 = 10;
std::string option_2 = "test2";
auto option_3 = 0.41;
std::vector<int> option_4(10);
int main() {
prototype p1(option_1, option_2, option_3, option_4);
prototype p2(option_1, option_2, option_3);
prototype p3(option_1, option_2);
prototype p4(option_1);
}
i would like to do so
std::cout << option_1 << std::endl;
if constexpr (std::tuple_size_v<decltype(p)> >= 3) {
std::cout << option_2 << std::endl;
}
I don't like this option std::get<0>(p)
Any ideas how to replace the call to tuple?
You can also see the option on https://godbolt.org/z/bT4Wzjco8
You can create a variable template out of a lambda. At the end of the day all you want is a compile time constant to pass to std::get:
template <std::size_t N>
constexpr auto option = [] (auto p) -> auto&& { return std::get<N-1>(p); };
This can be used as option<1>(p)
Demo
The familiar template syntax for lambdas may seem as another alternative:
constexpr auto option = []<std::size_t N>(auto p) { return std::get<N-1>(p); };
Here the argument to std::get is passed as a non type template parameter. As #Davis Herring mentions, this unfortunately does not mean the lambda is then to be used as option<1>(p). The reason being that the lambda is not itself a template, its function call operator is. The proposal changes nothing on the templateness of the lambda itself. As a result the lambda above is invocable as
option.operator()<1>(p)
Demo
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).
I am creating a class that allows me to store lambdas that need to be executed (in order) at a point in the future.
class Promise{
private:
//snip//
std::vector<std::function<void()>> lchain;
public:
//snip//
void then(const std::function<void()> &f){
if (this->resolved) {//If the promise is resolved we just call the newly added function, else we add it to the lchain queue that will be processed later
f();
return;
}
lchain.push_back(f);
}
void launch(){
this->resolved = true;
for (auto &fun: this->lchain)
fun();
}
}
It is obvious that it will only work with lambdas with a signature like [&](){} but some of the tasks need to work with an arbitrary number of parameters of arbitrary types (both, parameters and types are known in advance, when the function is added to the queue).
An example driver program that currently works is
int main(){
Promise* p = new Promise([](){
std::cout << "first" << std::endl;
})->then([](){
std::cout << "second" << std::endl;
});
Promise->launch(); //In my code promise chains are picked up by worker threads that will launch them.
}
An example program I would like to execute:
int main(){
Promise* p = new Promise([](){
return 5;
})->then([](int n){
return n*n;
})->then([](int n){
std::cout << n << std::endl; //Expected output: 25
});
Promise->launch();
}
Things that I am struggling to do:
Storing lambdas of mixed signatures in a std::vector
Making the then() method call f with the arguments associated with f
Making the then() function return the result of f so it can be fed to the next lambda in the chain (preferably binding it before storing the lambda in the vector)
I have been searching in stackoverflow the whole day but the closest I got was this but I would like something that can be done in the then() method to simplify the program code as it would be a pain to bind every single lambda before calling the then() method.
I have something that I think does what you want. I'll start with an example and then introduce the implementation.
int main(){
Promise p([] {
return 5;
});
p.then([](int n) {
return n*n;
}).then([](int n) {
std::cout << n << '\n';
});
p.launch();
struct A { int n; };
struct B { int n; };
struct C { int n; };
Promise q([](A a, int n) {
std::cout << "A " << a.n << ' ' << n << '\n';
return B{2};
});
q.then([](B b) {
std::cout << "B " << b.n << '\n';
return C{3};
}).then([](C c) {
std::cout << "C " << c.n << '\n';
});
q.launch(A{1}, 111);
Promise<B(A, int)> r([](auto a, int n) {
std::cout << "A " << a.n << ' ' << n << '\n';
return B{5};
});
r.then([](auto b) {
std::cout << "B " << b.n << '\n';
return C{6};
}).then([](auto c) {
std::cout << "C " << c.n << '\n';
});
r.launch(A{4}, 222);
}
This outputs:
25
A 1 111
B 2
C 3
A 4 222
B 5
C 6
Some drawbacks:
Calling then after the promise has been resolved doesn't automatically call the function. Things get confusing in that situation and I'm not even sure if it's possible.
You can't call then multiple times on the same promise. You have to build a chain and call then on the result of the previous then.
If any of those drawbacks make this unusable, then you can stop reading this humongous answer.
The first thing we need is a way of getting the signature of a lambda. This is only used for the deduction guide so it isn't strictly necessary for the core concept to work.
template <typename Func>
struct signature : signature<decltype(&Func::operator())> {};
template <typename Func>
struct signature<Func *> : signature<Func> {};
template <typename Func>
struct signature<const Func> : signature<Func> {};
template <typename Ret, typename... Args>
struct signature<Ret(Args...)> {
using type = Ret(Args...);
};
template <typename Class, typename Ret, typename... Args>
struct signature<Ret (Class::*)(Args...)> : signature<Ret(Args...)> {};
template <typename Class, typename Ret, typename... Args>
struct signature<Ret (Class::*)(Args...) const> : signature<Ret(Args...)> {};
template <typename Func>
using signature_t = typename signature<Func>::type;
The next thing we need is a base class. We know the next promise must accept the return type of the current promise as an argument. So we know the argument type of the next promise. However, we don't know what the next promise will return until then is called so we need a polymorphic base to refer to the next promise.
template <typename... Args>
class PromiseBase {
public:
virtual ~PromiseBase() = default;
virtual void launch(Args...) = 0;
};
Now we have the Promise class itself. You can construct a promise with a function. As I alluded to above, a promise stores a pointer to the next promise in the chain. then constructs a promise from the given function and stores a pointer to it. There is only one next pointer so you can only call then once. There's an assertion to make sure this doesn't happen. launch calls the stored function and passes the result to the next promise in the chain (if there is one).
template <typename Func>
class Promise;
template <typename Ret, typename... Args>
class Promise<Ret(Args...)> : public PromiseBase<Args...> {
public:
template <typename Func>
explicit Promise(Func func)
: handler{func} {}
template <typename Func>
auto &then(Func func) {
assert(!next);
if constexpr (std::is_void_v<Ret>) {
using NextSig = std::invoke_result_t<Func>();
auto nextPromise = std::make_unique<Promise<NextSig>>(func);
auto &ret = *nextPromise.get();
next = std::move(nextPromise);
return ret;
} else {
using NextSig = std::invoke_result_t<Func, Ret>(Ret);
auto nextPromise = std::make_unique<Promise<NextSig>>(func);
auto &ret = *nextPromise.get();
next = std::move(nextPromise);
return ret;
}
}
void launch(Args... args) override {
if (next) {
if constexpr (std::is_void_v<Ret>) {
handler(args...);
next->launch();
} else {
next->launch(handler(args...));
}
} else {
handler(args...);
}
}
private:
using NextPromise = std::conditional_t<
std::is_void_v<Ret>,
PromiseBase<>,
PromiseBase<Ret>
>;
std::unique_ptr<NextPromise> next;
std::function<Ret(Args...)> handler;
};
Finally, we have a deduction guide.
template <typename Func>
Promise(Func) -> Promise<signature_t<Func>>;
Here's an online demo.
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);
}
I am creating a lua binding in C++11. I want to process each type in a variadic template.
I was thinking I could do something like this, except using Params... represents all of the types inside of it, and not a the next single type inside of it like variadic function parameters do.
template <class T, typename ReturnType, typename... Params>
struct MemberFunctionWrapper <ReturnType (T::*) (Params...)>
{
static int CFunctionWrapper (lua_State* luaState)
{
for(int i = 0; i < sizeof...(Params); i++)
{
//I want to get the next type, not all of the types
CheckLuaValue<Params...>();
//Do other stuff
}
}
};
How would I go about doing this?
You can do this by simply expanding after the function call, into something that can be expanded to.
// put this in your namespace
struct Lunch { template<typename ...T> Lunch(T...) {} };
// and this instead of the for loop
Lunch{ (CheckLuaValue<Params>(), void(), 0)... };
You can do something else with a lambda. You can even have your i incremented
static int CFunctionWrapper (lua_State* luaState)
{
int i = 0;
Lunch{
(CheckLuaValue<Params>(),
[&]{ std::cout << "That was param " << i << std::endl; }(),
++i)...
};
}
Note that the Standard supports putting everything into the lambda. Compiler support until recently (last time I checked) wasn't very good though
static int CFunctionWrapper (lua_State* luaState)
{
int i = 0;
Lunch{([&]{
CheckLuaValue<Params>();
std::cout << "That was param " << i << std::endl;
}(), ++i)...
};
}