Using a pair as a parameter from another function - c++

I asked this question before but the suggestions don't work so I have tried to make my question more clear.
I have a function that returns a std::pair<int, double> but the parameters for the function as follow function(int g, double a);. This function then using make_pair to make a pair with the first being the int and the second being the double. It returns the pair.
I want to create another function to use the pair from the previous function and view the data in the pair, i.e. both first and second. Is it possible to pass the return of the previous function as a parameter for my new function so the second function can view the data? I am unsure about the syntax in C++.

It wouldn't be so hard if you rather not talked about the code but started trying to write it:
#include <iostream>
#include <utility>
std::pair<int, double> function(int g, double a)
{
return std::make_pair(g, a); // or return {g, a};
}
void print(std::pair<int, double> pair) // or take by reference-to-const
{
std::cout << pair.first << " " << pair.second << std::endl;
}
int main()
{
print(function(4, 5.5));
return 0;
}
Something's not in order if you're dealing with class templates, but don't know how to write functions.

Related

Lambda function, arguments and logic in c++ [duplicate]

This question already has answers here:
How does comparator function of c++ STL sort work?
(1 answer)
how does sort function in c++ work? [closed]
(2 answers)
Closed 1 year ago.
I am new to using lambda functions in C++. I have been researching the web, and found several articles, explaining the syntax and purpose of lambda function, but I have not come found articles which are clearly giving an explaining how to write the inner logic of a lambda function.
For example
During sorting a vector in c++ in decreasing order:
sort(v1.begin(), v1.end(), [](const int &a, const int &b){return b < a;});
I write the above code. Here, I have a few questions:
Why do I only provide two parameters in the lambda function? Why not three? or why not I give all the n parameter(n is size of vector) and do a logic? I am not trying to find maximum of two elements, I am trying to sort a vector, why should I only consider two values?
Why does a > b gives descending order? Why not b > a? Are there any kind of ordering inside the lambda function?
The return value in the above lambda function is either false(0) or true(1)? Why do I only have to return false(0) or true(1) to sort? Why can't I return a character to sort, like let's suppose for return value 'a' it is ascending and return value 'd' it is descending?
Again
During finding the max even element
itr = max_element(v1.begin(), v1.end(), [](const int &a, const int &b){
if (isEven(a) && isEven(b)) {
return (a < b);
} else
return false;
}
);
I am returning b > a. Rather than a greater than b. ???
Any suggestion would be greatly appreciated.
Your question has nothing to do with lambdas, but with the std::sort function.
Indeed, if you read the documentation about the third parameter (the comparison function, the lambda in your case), it says:
comparison function object which returns ​true if the first argument is
less than (i.e. is ordered before) the second.
The signature of the comparison function should be equivalent to the
following:
bool cmp(const Type1 &a, const Type2 &b);
Indeed, there is not need to create a lambda to pass it as the third parameter. You can pass any function object that receives two arguments of type T (the one of your container's elements) and returns bool.
For example, you can do something like this:
#include <vector>
#include <algorithm>
#include <iostream>
struct {
bool operator () (int a, int b){
return a > b;
}
}my_comp;
int main(){
std::vector<int> v={1,2,3};
std::sort(v.begin(), v.end(), my_comp);
for(auto e:v) std::cout << e << " ";
std::cout << std::endl;
}

Making a list of generators (vector of lambdas) leads to very strange behavior with capture-by-reference

The following code is fairly similar to my actual application. Basically, I am trying to create a vector of functions so that I can generate a very large output in segments. I don't fully understand how the capture by reference [&] is working / should be working, and it's leading to some weird behavior.
#include <iostream>
#include <functional>
#include <vector>
using namespace std;
template <typename T>
T add(const T& a, const T& b) {
return a + b;
}
template <typename T>
T add(const T& a, const T& b, T x) {
return (add<T>(a,b)*x);
}
int main() {
std::cout << "Hello World!\n";
vector<function<long ()>> funks;
for (long i = 1; i < 12; ++i) {
//auto funky = std::bind(add<int>, i, i*i);
std::cout << "PROOF: " << add(i, i*i, 2L) << std::endl;
function<long ()> funky = [&]() -> long {
long V = i;
return add(V, V*V, 2L);
};
funks.push_back(funky);
}
for (auto&& x : funks) {
std::cout << x() << " ";
}
}
The output of running each x in funks is: [312, 312, 312 ... 312] corresponding to i = 13
However, I don't understand why this is the case, as I reinitialize V for each lambda, and the output should be [4, 12, 24, 40, ... 264]
It works when I change the capture clause to [=], but in my actual application the inputs will be quite large so I'd prefer to copy as few times as possible.
EDIT: I should clarify exactly what I'm looking for. I'd like to make a vector of N functions, [f_0, f_1, ... f_N], such that when calling f_i(), it calls F(V_i) for some large (known) function F and large V_i.
The reason I want to capture by reference is that I don't want to copy the V_i even once, but the result of my implementation is that every f_i() ends up calling F(V_N)
You are auto-capturing i by reference in your loop, but it's only a binding. The value is not actually used until after the loop, when calling the lambda. At that point, each call takes the captured "reference to i" (which is actually undefined behavior, given that i is no longer in scope), dereferences it and stores the value in V. You know the rest.
What is strange is that you are insisting on using references to integer values. It's likely the compiler is doing its best to inline these and just use plain copies, but you should consider that when you have a reference, you can often expect additional instructions to be generated to dereference that to a value. For primitive types, just copy.
Oh, and definitely capture i by value!!! As a matter of style, I prefer to be explicit about my captures:
function<long ()> funky = [i]() -> long {
long V = i;
return add(V, V*V, 2L);
};

Passing a pointer for a dynamic runtime function

I'm trying to write a generic utility function for a class that applies a function to each element of a vector with the only input argument being the value of that element. The idea being that I can use that to support scalar addition/multiplication as well as user-specified functions without duplicating too much code. It works fine for the user-specified functions, but I'm struggling with how the best implement it for scalar addition/multiplication.
The code below is a simplified version of what I'm playing around with. It works fine, but what I want to be able to do is have the "5" in the lambda expression be a variable passed in separately, but not necessarily passed into "apply_f". So keep apply_f only taking a vector an a function pointer. I'm aware of the captures field for lambda expressions, but I was having trouble passing a lambda function with a capture into another function. I'm also aware of something like std::bind, but couldn't get that to work either.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
void apply_f(vector<double>& vec, double (*f)(double)) {
transform(vec.begin(), vec.end(), vec.begin(), f);
}
int main() {
vector<double> x {1, 2, 3};
auto f = [](double x){ return x + 5; };
apply_f(x, f);
cout << x[0] << endl;
cout << x[1] << endl;
cout << x[2] << endl;
}
Simply take a parameter with a unique type:
template <class F>
void apply_f(vector<double>& vec, F f) {
transform(vec.begin(), vec.end(), vec.begin(), f);
}
Not only it will work, but you will get way better performance since the compiler knows the actual type being passed.
Unfortunately, lambdas are not just pointers to functions (because they can have state, for instance). You can change your code to use a std::function<double(double) instead of a double(*)(double), and this can capture a lambda (you may need to pass std::cref(f) instead of just f).

How do you create a vector of function pointers that can take different arguments?

I'm trying to learn how to store functions (or rather pointers to functions) in std::vector. I have this code:
#include <iostream>
#include <vector>
void x(int i)
{
std::cout << "x is " << i << std::endl;
}
void y(int i, int j)
{
std::cout << "y is " << i << " and " << "j" << std::endl;
}
int main()
{
std::vector<void(*)(int)> V;
V.push_back(x);
V[0](1);
return 0;
}
This works perfectly but the problem is that I can't push_back function y into the same vector since it takes 2 integers instead of one.
What should I do to store both functions in the same vector?
There is no good way to do what you want, but you can do it.
Write an augmented variant (std or boost or hand rolled tagged typesafe union) that supports implicit cast-from with exception if you get the type wrong (feel free to support conversion between types if desired). Call this poly_arg<Ts...>
Write a type eraser that takes an arg type as a template parameter. It then takes a function pointer at construction, and type erases calling it with a vector of just the right length of arguments. (Or a function object and an arg count range). It then has a vararg operator() that forwards its arguments into a vector of its arg type, then tries to call using the above type erasure. If the wrong number of arguments is passed, it throws an exception. Call this vararg_func<T>.
Store a vector of vararg_func<poly_arg<int, double, std::string>> (list of 3 types is just an example). This can store void(*)(int) and void(*)(int,int) and void(*)(std::string, double, int) and void(*)() etc, and you can invoke it. If you get the argument count wrong, you get an exception (from vararg func). If you get an argument type wrong, exception (from poly arg). If you pass an incompatible function pointer, compile error at push_back (which is great!)
If you only need to support int args you can skip poly_arg and store vararg_func<int> instead.
I think this is a bad plan.
You very very rarely want to treat functions with different numbers and types of arguments uniformly. The few legitimate cases are best handled with two coupled type erasing systems (like efficient massive customization point tables with non-uniform signatures) that hide the type unsafety internally.
Instead this plan matches your requirements, which forces type unsafety in its interface and pollutes your code with "dunno, maybe it will work" calls.
If you want help implementing those type erasers, realize that I both know how to write them and how they solved your problem and in my opinion they are a really bad idea. If that fails to deter you, go and learn about type erasure in C++ and value-type polymorphism and how std::function works. Try to write a toy std::function. Play with a "view-only" and "move-only" version. Try a zero-allocation with bounded function object size. That should take a few weeks or years.
Now write some more simple cases, like printing to an ostream. Get good enough at it. At which point vararg_func shoukd be challenging but doable; try it. If it fails, ask SO to help, including your attempt.
poly_arg should be easy in comparison.
What you want is neither possible nor reasonable. It's not possible because function pointers are typed, and a pointer to a void(int, int) is a different type from a pointer to a void(int). vector is a homogeneous container; all of its elements must be the same type. And the two types are unrelated; you cannot cast the pointer to one type into a pointer to another and expect calling it to work.
The best you can do is use a variant of pointers to different function types. Now, I have no idea how you would call those functions, since the different types take different parameter lists. How could you call it through a visitor functor? Do you have enough parameters to forward to the function in question? If not, then what's the point?
Unless you know a priori that index X in the list has a specific parameter list, and you have those parameters to pass to it, then there is no effective way to call it. And if you do know that, then what you probably want is a tuple or struct of function pointers, not a runtime container of them.
You could use std::variant if you have access to C++17:
#include <variant>
std::vector<std::variant<void(*)(int), void(*)(int, int)>> V;
V.push_back(x);
V.push_back(y);
But this gets messy real fast (if you want to add even more function types etc) and since there are different parameter types and amounts there's no sure way to uniformly call them from out of the vector unless you also store their type information and std::get the correct variant.
First of all, i would recomend using std::function over function pointers. They are more generic and can be filled with a function pointer, function object or lambda expression. The typical useage looks like this:
#include <iostream>
#include <functional>
struct Funktor { // This is a callable class/object
void operator()() {
std::cout << "Funktor called." << std::endl;
}
};
void function() { // Normal function
std::cout << "Function called." << std::endl;
};
int main()
{
std::function<void()> lambdaFunction = [](){ std::cout << "lambda function executed." << std::endl;}; // And a lambda expression (fancy way to write a function where you need it)
std::function<void()> functionPointer = &function;
std::function<void()> callableObject = Funktor();
//This is the way you call functions with a std::function object, just like with a normal function
lambdaFunction();
functionPointer();
callableObject();
return 0;
}
But this does not solve your problem of storing functions with different arguments in a std::vector. Since they have a differen signature you have to treat them as if they are different types. Like int and std::string.
To store elements with different types, the STL offers std::tuple. You can use this one to achieve your goal.
#include <iostream>
#include <functional>
#include <tuple>
int main()
{
// std::tuple takes multiple template arguments. Each corresponds to one element in the tuple
std::tuple<
std::function<void()>,
std::function<void(int)>
> functionTuple;
// To access a element of the tuple we call std::get<i> on the tuple
// This will return a reference to the element in the tuple and we
// can overwrite it with whatever we want
std::get<0>(functionTuple) = [](){
std::cout << "Function without arguments." << std::endl;
};
std::get<1>(functionTuple) = [](int arg){
std::cout << "Function without int as argument. Arg = " << arg << std::endl;
};
// We use std::get to get the function and the call it.
// The the trailing '()' and '(5)' are the actual function calls,
// just like in the example above
std::get<0>(functionTuple)();
std::get<1>(functionTuple)(5);
// You can also use std::get<...> with a type as argument.
// Have a look in the docs. Its a very nice feature of tuples
return 0;
}
And if you want to achieve both, different arguments and multiple functions, you can combine std::tuple and std::vector:
#include <iostream>
#include <functional>
#include <tuple>
#include <vector>
int main()
{
std::tuple<
std::vector<std::function<void()>>,
std::vector<std::function<void(int)>>
> functionTuple;
// We use push_back in this example, since we deal with vectors.
std::get<0>(functionTuple).push_back([](){
std::cout << "Function without arguments." << std::endl;
});
std::get<1>(functionTuple).push_back([](int arg){
std::cout << "Function without int as argument. Arg = " << arg << std::endl;
});
std::get<1>(functionTuple).push_back([](int arg){
std::cout << "Another function without int as argument. Arg = " << arg << std::endl;
});
std::get<0>(functionTuple).front()();
int i = 5;
// And we use foreach, to loop over all functions which take one integer as argument
for(auto& f : std::get<1>(functionTuple)) {
f(i);
i += 5;
}
return 0;
}
That all beeing said, I will add a word of caution. Function pointers/objects and lambdas are only one tool. They are very flexible and powerful and because of this can lead you into a rabbit hole of unexpected behaviour and errors. If you do not plan to write very generic algorithms and go deep into template metaprogramming, this tool is most likely not the best to do the job. Going for different solutions like the command pattern can make your life much easier.
Another possibility would be to alter the signature of 'x' to match that of 'y', by adding an additional int parameter that could be ignored by the body of x.
Easy. Place the arguments into a structure or base class.
If you use a pointer to a base class, you can expand the genericity.
An old fashioned method is to pass a void pointer and have the function cast it correctly.
In fact you cannot push different pointer to function of different signatures into a vector as long as you cannot push different objects of different types into a vector.
class A{};
class B{};
A aObj;
B bObj;
std::vector<class A> vecA;
vecA.push_back(aObj); // ok
vecA.push_back(vecB); // error
Push only objects with the same type as your vector instance require:
#include "stdafx.h"
#include <iostream>
#include <vector>
void Foo() { std::cout << "Foo()" << std::endl; }
void Foo2() { std::cout << "Foo2()" << std::endl; }
int Bar(float) { std::cout << "Bar(float)" << std::endl; return 0; }
double Baz(int, int) { std::cout << "Baz(int, int)" << std::endl; return 0; }
int main(){
std::system("color 1f");
typedef void(*pFunc1)();
typedef int(*pFunc2)(float);
typedef double(*pFunc3)(int, int);
pFunc1 pFn1 = Foo;
pFunc1 pFn2 = Foo2;
//pFunc1 pFn3 = Bar; // error here I guess you k now why
std::vector<pFunc1> pvcFunc1;
std::vector<pFunc2> pvcFunc2;
std::vector<pFunc3> pvcFunc3;
pvcFunc1.push_back(pFn1);
pvcFunc1.push_back(pFn2);
for (int i(0); i < pvcFunc1.size(); i++) {
pvcFunc1[i]();
}
std::cout << std::endl << std::endl << std::endl;
std::cin.get();
return 0;
}
I wouldn't do that.
I can't tell you whether using both functions in one vector is possible or not -- I'm pretty sure it isn't.
You should instead make a class and use a vector of objects.

How to write my own functions for comparison?

I wrote a function for vector comparison.
#include <vector>
#include <iostream>
#include <algorithm>
using std::vector;
using std::cout;
bool mycomp(const vector<int>& vi_a, const vector<int>& vi_b){
for(auto x:vi_a) cout << x;
cout << '\n';
return true;
}
int main(){
vector<int> vi1{2,9,8};
vector<int> vi2{3,5,6};
vector<int> vi = min(vi1, vi2, mycomp);
for(auto x:vi) cout << x;
cout << '\n';
}
Output:
356
356
What's weird is that the output is 356, instead of 298. It seems that the two vectors are switched when calling mycomp.
p.s. I'd rather not use lambda here, because mycomp contains more than one line of code, which is more readable this way.
If you take a look at the cppreference documentation for std::min() you will see in the possible implementation that the second element is used as the first element in the comparator.
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp)
{
return (comp(b, a)) ? b : a;
}
And when you call min() with the arguments vi2 and vi1, the second argument is passed to the comparator (which in your case is vi2), upon which the comparator returns true (implying that vi2 is the minimum of the two). While doing this the comparator also prints out 356 because that is the first element passed to the comparator according to the possible implementation above.
After that happens you take the presumably smaller of the two vectors, which is the first one passed to the comparator according to the possible implementation above (which is vi2). And you print that out. Therefore you get 356 again.
Note that the reason b is passed as the first argument to std::min is because in the case where the two compare equal the algorithm is required to return a. At the same time it is required to call the comparator only once. Combining these two requirements gives the possible implementation above.