Can someone explain to me what does this piece of code step by step? I found it in this topic : Segmentation fault on gcc caused by lambda wrapper over variadic template function call and I don't understand nothing :
template <typename TNode, typename... TNodes>
auto execute(TNode& n, TNodes&... ns)
{
[&](){ n.execute(ns...); }();
}
Especially the part : [&](){ n.execute(ns...); }();
Is there any connection with lambda calculus and programmation language like caml or ocaml?
Thank you in advance
This part [&](){ n.execute(ns...); }(); creates a new lambda and execute it directly. It is equal to:
auto temp= [&](){ n.execute(ns...); };
temp();
This part n.execute(ns...); is calling a member function called TNode::execute which accepts many parameters (variadic template argument) of the types TNodes...
Related
template<typename ...>
bool foo(std::tuple<std::string,float> bar...)
{
std::vector<std::tuple<std::string,float>> barList(bar...);
// ...
}
This does not seem to generate any syntax error. There is no error indicator at that line in the editor, but the compiler stops with
[bcc32c Error] Foo.cpp(117): pack expansion does not contain any unexpanded parameter packs
I tried to read online, but all examples I find either seem incomplete, or are not clear to me.
A simple answer to why this does not compile would be appreciated.
Your syntax is wrong. Your function is equivalent with:
bool foo(int bar...)
{
std::vector<int> barList(bar...);
// ...
}
Notice there is no variadic templates at all, and there is nothing to unpack - instead, you have created a C-style variadic function.
One easiest way to change your function would be:
template<typename... Args>
bool foo(Args... bar)
{
std::vector<std::tuple<std::string,float>> barList({bar...});
// ...
}
This is not ideal, as it makes your template function quite greedy - it will gladly consume any arguments, not just tuples of strings and floats.
We can spice it up by using C++20 concepts:
template<class T>
concept Tuple = std::is_same_v<T, std::tuple<std::string, float>>;
template<Tuple... T>
bool foo(T... bar)
{
std::vector<std::tuple<std::string, float>> barList({bar...});
// ...
return true;
}
This allows usage like that:
foo(std::tuple<std::string, float>{"ddd", 20}, std::tuple<std::string, float>{"ddd", 20});
But not like that:
foo(10, 20, nullptr);
I'm working with a C++ code that I've found online. The creator of this code insists that this code works, but I cant get the code to compile and run no matter what I do. In particular, i'm getting two errors, which are:
no instance of function template "Defer" matches the argument list
TDefer<DoPkg::<lambda_cbb42bad95cffc2340696a1e41564dae>> Defer<DoPkg::<lambda_cbb42bad95cffc2340696a1e41564dae>>(T &)': cannot convert argument 1 from 'DoPkg::<lambda_cbb42bad95cffc2340696a1e41564dae>' to 'T&'
The portion of the code where the above two errors are occurring is as follows:
bool DoPkg(const wchar_t* pPath, const wchar_t* pOutputPath) {
std::map<int, FILE*> files;
int mainPackageIndex = LoadPackages(pPath, files);
auto defer = Defer([&files]() -> void{
for (auto it : files){
fclose(it.second);
}
});
//More Code here...
return true;
}
The function being called in the auto defer part is:
template<typename T> TDefer<T> Defer(T & callback){
return TDefer<T>(callback);
I have tried to search for fixes to these issues, but I can't figure out how to fix them.
Defer takes an non-const lvalue reference. Your lambda expression that you have in the call site creates a temporary object, and temporary objects can't bind to non-const lvalue references.
You either need to change Defer to be
template<typename T> TDefer<T> Defer(T && callback)
// or
template<typename T> TDefer<T> Defer(T callback)
// or no template and use
TDefer<std::function<void()>> Defer(std::function<void()> callback)
So it can accept lvalues and temporaries, or make the lambda an object and then pass it to Defer like
auto temp = [&files]() -> void{
for (auto it : files){
fclose(it.second);
}
};
auto defer = Defer(temp);
This is the code that cause the warning:
inline auto getclock() { return std::chrono::steady_clock::now(); }
inline auto getelapsed(auto b, auto e) { return std::chrono::duration_cast<std::chrono::nanoseconds>(e-b).count(); }
//USAGE: auto b=getclock(); some_func_to_be_timed(...); auto duration=getelapsed(b, getclock()); ..
This code compiled without problem before I recently upgraded to gcc 8 (c++17), now I get the warning as stated in the question.
Why would I get this warning now, and how should I handle it?
PS: I don't use concepts (explicitly) anywhere in the rest of the code.
auto as parameter are not allowed for regular functions in C++17.
(It is in C++20).
You might use regular template, something like:
template <typename T> // or T1, T2 to mimic your code
auto getelapsed(T b, T e)
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(e-b).count();
}
This question already has answers here:
Variadic function template with pack expansion not in last parameter
(4 answers)
Closed 6 years ago.
I was able to find one question on SO that seems to be asking the same or similar question that I am, but there are no answers :-(
I'd like to place a non-template parameter after a parameter pack. I'm not too familiar on the C++ standard specification for variadic templates / parameter packs, but my common sense assumption tells me that the right-most parameters passed to a function would be filled into placement parameters first, then the rest get filled into the parameter pack. However, I'm not able to get my test code working on either g++ or clang++. Sample code below.
#include <vector>
#include <iostream>
int Subscribe(int channel, int callback)
{
return channel;
}
// This one works fine...
template<typename... T>
std::vector<int> SubscribeMultiple1(int callback, T&&... channels)
{
return {
Subscribe(std::forward<T>(channels), std::move(callback))...
};
}
// This one does not work; all I did was move `int callback` after the parameter pack.
template<typename... T>
std::vector<int> SubscribeMultiple2(T&&... channels, int callback)
{
return {
Subscribe(std::forward<T>(channels), std::move(callback))...
};
}
int main()
{
auto subs = SubscribeMultiple2(1, 2, 3);
for (auto sub : subs)
{
std::cout << "Sub: " << sub << '\n';
}
}
Live Sample
So my first question is, why does the non-template parameter not work after the parameter pack? Am I doing something wrong or is this prohibited by the language?
Secondly, is there any way to get the syntax I'm trying to do? I've oversimplified my sample, but in my real code the callback parameter is really a std::function<...>. The idea is I can subscribe to a number of "event IDs", and the callback is defined at the end. Having the callback at the end is better for readability and style. Example:
SubscribeMultiple(EventOne, EventTwo, EventThree, [] {
// Implement callback code here when any of the above
// three events are fired.
});
If I have to have the callback in the front, it's less readable IMHO. So I'm willing to try any workaround to get the syntax and structure I'm aiming for. Thanks in advance.
Am I doing something wrong or is this prohibited by the language?
Deduction of parameter packs occurs only when the pack is the last argument.
[temp.deduct.type]/5.7:
The non-deduced contexts are:
[...]
A function parameter pack that does not occur at the end of the parameter-declaration-list.
So that's normal behavior of standard C++.
is there any way to get the syntax I'm trying to do?
Use the first syntax as a workaround:
template<typename... T>
std::vector<int> SubscribeMultiple1(int callback, T&&... channels)
While building a small lambda-based metaprogramming library, I had the necessity of using recursion in a C++14 generic lambda, to implement a left-fold.
My own solution was passing the lambda itself as one of its parameters, like this:
template <typename TAcc, typename TF, typename... Ts>
constexpr auto fold_l_impl(TAcc acc, TF f, Ts... xs)
{
// Folding step.
auto step([=](auto self)
{
return [=](auto y_acc, auto y_x, auto... y_xs)
{
// Compute next folding step.
auto next(f(y_acc, y_x));
// Recurse if required.
return static_if(not_empty(y_xs...))
.then([=]
{
// Recursive case.
return self(self)(next, y_xs...);
})
.else_([=]
{
// Base case.
return next;
})();
};
});
// Start the left-fold.
return step(step)(acc, xs...);
}
step is the "main" lambda that starts off the recursion. It returns a function with the desired left-fold signature (accumulator, current item, remaining items...).
The function calls itself recursively by using self(self)(next, y_xs...).
I've recently come across this proposal that wants to add a Y Combinator to the Standard Library, and after reading it, it seems extremely similar to what I am doing here.
Unfortunately, the concept of the Y Combinator still doesn't "click" for me - I am missing something and I cannot visualize how to generalize what I did with the self parameter for any function, avoiding the step boilerplate.
I've read this excellent StackOverflow answer regarding the matter, but it still didn't "click" for me.
(From that answer) a recursive factorial is defined this way:
fact =
(recurs) =>
(x) =>
x == 0 ? 1 : x * recurs(x - 1);
The recurs parameter seems to have the same role as my self parameter. What I do not understand is how recurs is called without passing recurs into itself again.
I have to call self like this: self(self)(params...).
recurs, however, is called like recurs(params...).
Attempting to call self(params...) results in a compiler error informing me that self requires only a single parameter (which is the auto self lambda parameter).
What am I missing here? How could I rewrite my fold_l_impl lambda in such a way that its recursion could be generalized through the use of a Y Combinator?
Here is a y combinate where the lambda is passed a recurs that doesn't need to be passed recurs:
template<class F>
struct y_combinate_t {
F f;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return f(*this, std::forward<Args>(args)...);
}
};
template<class F>
y_combinate_t<std::decay_t<F>> y_combinate( F&& f ) {
return {std::forward<F>(f)};
};
then you do:
return y_combinate(step)(acc, xs...);
and change
return self(self)(next, y_xs...);
to
return self(next, y_xs...);
the trick here is I used a non-lambda function object that has access to its own this, which I pass to f as its first parameter.