How to pass a name for convenient use of tuple? - c++

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

Related

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 avoid storage overhead when using a function as a callback?

Given the following setup:
// ***** Library Code *****
#include <concepts>
template <std::invocable CbT>
struct delegated {
explicit constexpr delegated(CbT cb) : cb_(std::move(cb)) {}
private:
[[no_unique_address]] CbT cb_;
};
// ***** User Code *****
#include <iostream>
namespace {
inline constexpr void func() {}
}
struct MyFunc {
constexpr void operator()() const {}
};
int main() {
void (*func_ptr)() = func;
auto from_func = delegated{func};
auto from_func_ptr = delegated{func_ptr};
auto from_lambda = delegated{[](){}};
auto from_functor = delegated{MyFunc{}};
std::cout << "func: " << sizeof(from_func) << "\n";
std::cout << "func_ptr: " << sizeof(from_func_ptr) << "\n";
std::cout << "lambda: " << sizeof(from_lambda) << "\n";
std::cout << "functor: " << sizeof(from_functor) << "\n";
}
It produces, on GCC-x86-64 (See on godbolt):
func: 8 <----- Unfortunate
func_ptr: 8 <----- Fair enough
lambda: 1 <----- Neat
functor: 1 <----- Neat
None of this is particularly surprising.
However, it's frustrating that an undecayed lambda is preferable to using a function. And adding a note that delegated{[]{func();}} reduces the storage overhead is not exactly user-friendly, and makes for a very poor library interface.
Is there a way to do away with the storage overhead in the func case while maintaining a consistent user-facing API?
My current suspicion is that this is not possible without resorting to macros, on account of func not having, or decaying into, any type that would distinguish it from other functions with the same signature. I'm hoping that I overlooked something.
N.B. I get that something along the lines of delegated<func>() is a possibility, but unless I can prevent delegated{func} while still allowing delegated{func_ptr}, then that would be practically pointless.
Edit: To clarify the context a little bit: I am writing delegated in a library, and I don't want users of said library to have to worry about this. Or at least have the process be compiler-assisted instead of being documentation-dependant.
There are no objects of function types. The type will be adjusted to be a function pointer, which is why you delegated{func} and delegated{func_ptr} are exactly the same thing and former cannot be smaller.
Wrap the function call inside a function object (lambda, if you so prefer) to avoid the overhead of the function pointer.
If you would like to prevent the accidental use of the adjusted/decayed function pointer case when user tries to pass a function, then you could use a deleted overload for function references. I don't know how that could be achieved with CTAD, but if you provide a function interface, it could be done like this:
constexpr auto
make_delegated(std::invocable auto CbT)
{
return delegated{std::move(CbT)};
}
template<class... Args>
constexpr auto
make_delegated(auto (&cb)(Args...)) = delete;
Edit: Combining ideas with Human-Compiler's answer
template <auto CbT>
constexpr auto
make_delegated_fun() {
return delegated{ []{ CbT(); } };
}
constexpr auto
make_delegated(std::invocable auto CbT)
{
return delegated{std::move(CbT)};
}
template<class... Args>
constexpr auto
make_delegated(auto (&cb)(Args...)) {
// condition has to depend on template argument;
// just false would cause the assert to trigger without overload being called.
static_assert(!std::is_reference_v<decltype(cb)>, "please use make_delegated_fun");
};
auto from_func1 = make_delegated(func); // fails to compile
auto from_func2 = make_delegated_fun<func>(); // OK
auto from_func_ptr = make_delegated(func_ptr); // OK, pointer overhead
auto from_lambda = make_delegated([](){}); // OK
auto from_functor = make_delegated(MyFunc{}); // OK
Caveat, this would prevent following, and the example wouldn't work using make_delegated_fun either so the message would be misleading. The example could easily be rewritten to use function pointers or capturing lambda though:
auto& fun_ref = condition ? fun1 : fun2;
make_delegated(fun_ref); // fails to compile, suggests make_delegated_fun
make_delegated_fun<fun_ref>(); // fails to compile, not constexpr
make_delegated(&fun_ref); // OK, pointer overhead
The only way to really remove the "storage" from a function like this is to use the value at compile-time. The only real way to accomplish this is through a non-type template argument.
A factory function could do this easily with little changes, and keeps the implementation simple. You just need to accept the callable object as a template non-type argument -- such as an auto parameter, so that its known at compile-time without any storage requirements.
One way to perform this is to just use your lambda-wrapping solution with the existing code:
template <auto Fn>
auto make_delegated() {
return delegated{ []{ Fn(); } };
}
Then the following works:
auto from_func = make_delegated<&func>();
std::cout << "func: " << sizeof(from_func) << "\n";
this yields the correct value:
func: 1
Live Example
As an alternative measure, you could also require the user to wrap the function itself in a sentinel type that carries the data:
template <auto Fn>
struct empty_func{
auto operator()() { return Fn(); }
};
This would be almost equivalent to using a lambda, though the user instead only has to do:
auto from_func = delegated{empty_func<&func>{}};
The point is just that the function needs to be carried at compile-time somewhere.
Passing the function pointer as a template argument does not require any space at runtime. For example:
template <auto F>
struct delegated_erased {
template <typename... argument_t>
auto operator()(argument_t&&... argument){
F(std::forward<argument_t>(argument)...);
}
};
auto from_func = delegated_erased<func>{};
std::cout << "func: " << sizeof(from_func) << "\n"; // 1
With a helper function, you can combine this with your code:
template <typename result, typename ... argument>
delegated<result> make_delegated(result(&)(argument...)) = delete;
template <typename T>
delegated<T> make_delegated(T f) {
return delegated{std::move(f)};
};
template <auto F>
delegated_erased<F> make_delegated(){
return {};
}
Which allows you to do:
auto from_func = make_delegated<func>();
//auto from_func = make_delegated(func); // error: call to deleted function 'make_delegated'
auto from_func_ptr = make_delegated(func_ptr);
auto from_lambda = make_delegated([](){});
auto from_functor = make_delegated(MyFunc{});

Parsing lambda to a function using templates

I am quite new to C++ and I am currently trying to learn how to utilize a template for a lambda function.
The lambda can be seen in the main function, and it simply makes a boolean check.
The implementation below works, but I have to explicitly state the types of the lambda in the testing function, as seen in the input parameter.
void testing(std::function<bool(const int& x)> predicate){
auto a = predicate(2);
std::cout << a << "\n";
}
int main() {
int ax = 2;
testing([&ax](const int& x) { return x == ax;});
}
I wish for an implementation where I can utilize templates as seen below, but I can not get anything to work.
template <typename T>
void testing(std::function<bool(const T& x)> predicate){
auto a = predicate(2);
std::cout << a << "\n";
}
Is there a general way to utilize a template for lambdas?
Don't wrap the template parameter in std::function.
The best way to pass a lambda to a function is to just have it as an unconstrained template parameter:
template<class F>
void testing(F predicate) {
auto a = predicate(2);
std::cout << a << '\n';
}
int main() {
int ax = 2;
testing([ax](int x) { return x == ax; });
}
Benefits over std::function.
std::function allocates space on the heap to store the functor
std::function has an overhead similar to a virtual function call
std::function can't be inlined by the compiler, but it's trivial to inline a lambda that's passed directly

Is base case function mandatory or could it be automatically synthesized?

In the following code :
void print()
{
// This is our base case fn
;; // Do nothing
}
template <typename type1, typename... argspack>
void print(type1 a, argspack... args_rest)
{
cout << a << ((sizeof...(args_rest) != 0) ? "," : "\n");
print(args_rest...); // I guess this recursive call is inevitable
}
If the recursive call to variadic function is inevitable, the base case function is also inevitable. If so, is there a language feature, perhaps one
that comes with modern c++, that help a programmer get away without writing a base case function?
Another (slightly elaborate) way which avoids recursion and a trailing comma:
#include <iostream>
#include <tuple>
struct linefeed {};
template<typename...Args>
void print(Args&&... args)
{
const char* sep = "";
auto print_with_sep = [&sep](auto& os, auto& arg)
{
if constexpr (std::is_same<std::decay_t<decltype(arg)>, linefeed>())
{
sep = "";
os << '\n';
}
else
{
os << sep << arg;
sep = ",";
}
};
auto print_all = [&](auto&&...things)
{
(print_with_sep(std::cout, things), ...);
};
print_all(args..., linefeed());
}
int main()
{
print(1,2,3,4,5, "hello");
print("world", 5,4,3,2,1);
}
expected output:
1,2,3,4,5,hello
world,5,4,3,2,1
https://coliru.stacked-crooked.com/a/770912eee67d04ac
A dummy is one way. Another is to make it a single argument function that actually does work:
template<typename T>
void print(T a)
{
std::cout << a;
}
template <typename type1, typename... argspack>
void print(type1 a, argspack... args_rest)
{
print(a);
std::cout << ((sizeof...(args_rest) != 0) ? "," : "\n");
print(args_rest...); // I guess this recursive call is inevitable
}
A benefit to this approach is that it provides a customization point too. If some type wants to provide its own print implementation, all it has to do is write the overload. ADL will find it and overload resolution will favor it.
To be perfectly clear, you have to write the base case yourself. The language doesn't consider those two functions as related beyond being overloads of the same name. It isn't even aware there needs to be a base case, that is our logical requirement.
You may refer to Fold Expression which is supported as of C++17.
I came up with the code almost similar to your code but it has a trailing comma.
template<typename... argspack>
void print(argspack&&... args) {
((cout << args << ","), ...) << "\n";
}
I am not sure there is a way to get exactly the same with your code using Fold Expression. Since we sizeof...(args) is always the initial size in this version.
With one function in C++11:
template <typename... Ts>
void print(Ts... args)
{
const char* sep = "";
const int dummy[] = {((std::cout << sep << args), (sep = ", "), 0)..., 0};
static_cast<void>(dummy); // Avoid warning for unused variable
std::cout << "\n";
}
dummy array trick can be replaced by fold expression in C++17:
template <typename... Ts>
void print(Ts... args)
{
const char* sep = "";
(((std::cout << sep << args), (sep = ", ")), ...);
std::cout << "\n";
}

Template function on struct members

Is there a way to code a single template function able to run on different members of a given struct ?
A wrong example would look like :
struct Foo
{
int a, b;
}
template <MEMBER x> //which does not exist
cout_member(Foo foo)
{
cout << foo.x << endl;
}
int main()
{
Foo foo;
cout_member<a>(foo);
cout_member<b>(foo);
return 0;
}
I imagined an answer based on a switch, but I then wondered if this switch would be tested on run-time (what I would like to avoid) or on compile-time ?
As long as you want to pick up a data member from a set of data members having the same type, you can use a pointer to data member:
template <int Foo::*M>
void cout_member(Foo foo)
{
std::cout << (foo.*M) << std::endl;
}
And use it as:
cout_member<&Foo::a>(foo);
If you want to indicate also the type, you can do this:
template <typename T, T Foo::*M>
void cout_member(Foo foo)
{
std::cout << (foo.*M) << std::endl;
}
And use it as:
cout_member<int, &Foo::a>(foo);
Just out of curiosity, the second snippet would be even simpler in C++17:
template <auto M>
void cout_member(Foo foo)
{
std::cout << (foo.*M) << std::endl;
}
See it up and running on wandbox;
You can leverage std::mem_fn so you don't even have to care: (untested)
template < typename Fun, typename ... Params >
void print(Fun f, Params && ... p) { std::cout << f(std::forward<Params>(p)...) << "\n"; }
print(std::mem_fn(&Obj::fun), Obj());
Since you're using streams you probably don't care...but this should add little to zero overhead from just writing cout << obj.fun().
Edit: mem_fn works on data members too. Creates a callable that returns a reference to the value that you can then use: int x = mem_fn(&pair<int,char>::first)(my_pair);