Rewriting ( set<pair<x,y>> ) as a struct - c++

I have to write this:
set<pair<float,int>>foo;
foo.insert(make_pair(a, b));
while (!foo.empty())
{
float dist = foo.begin()->first;
int u = foo.begin()->second;
}
But I want to use my own implementation without adding all the functionality of set/pair.
This is basically what I want pair to do:
struct pair2
{
float first;
int second;
pair2(float arg_first, int arg_second)
{
first = arg_first;
second = arg_second;
}
pair2 make_pair2(float first2, int second2)
{
return (pair2(first2,second2));
}
};
I'm not sure if that's completely correct, but I also have to implement set to work with it:
set<pair>foo; //not set<pair<float,int>>foo; since not templated
foo.insert(make_pair2(a,b));
What's the best way to do this? Should I implement set using a vector? All I need set to have is: empty(), begin(), erase() and insert() which vectors already have.

If I understand correctly, you want to have a pair that is "untemplated". You can type alias, which you can use to rename types to some custom type.
Instead of typing std::pair<float, int> each time, you could call it my_pair.
This is how you can do it in C++11:
#include <iostream>
#include <utility>
#include <set>
using my_pair = std::pair<float, int>;
my_pair make_my_pair(float a, int b) {
return std::make_pair(a, b);
}
int main() {
my_pair a(1.5, 2);
my_pair b = make_my_pair(2.2, 3);
std::cout << a.first << " " << a.second << std::endl;
std::cout << b.first << " " << b.second << std::endl;
std::set<my_pair> foo;
foo.insert(make_my_pair(3.4, 4));
return 0;
}
Be sure to compile with -std=c++11.
If you can't/don't want to use C++11 constructs, you can do this as well:
#include <iostream>
#include <utility>
#include <set>
typedef std::pair<float, int> my_pair;
my_pair make_my_pair(float a, int b) {
return std::make_pair(a, b);
}
int main() {
my_pair a(1.5, 2);
my_pair b = make_my_pair(2.2, 3);
std::cout << a.first << " " << a.second << std::endl;
std::cout << b.first << " " << b.second << std::endl;
std::set<my_pair> foo;
foo.insert(make_my_pair(3.4, 4));
return 0;
}

Related

When using variant but error-invoke, could errors happens in compiling time instead of bad_variant_access in running time

If I have a map like
const std::map<int, std::variant<int, std::string>> m ={{1,1},{2,"asd"}};
But if i invoke std::get<string>(m[1]) by mistake instead of std::get<int>(m[1]), it will raise bad_variant_access.
But it is just a typo of codes, so could it be detected by IDE, or some form of static_assert could work because m is a constant(or what if m is not a constant) , or raise only compile errors?
If it is always constant, you don't need a map. You can dispatch that at compile time:
#include <iostream>
template <int i>
constexpr auto m()
{
if constexpr (i == 1) {
return 1;
} else if constexpr (i == 2) {
return "hello";
}
}
int main()
{
std::cout << m<1>() << '\n';
std::cout << m<2>() << '\n';
}
Or, just use a tuple:
#include <iostream>
#include <tuple>
int main()
{
std::tuple tuple { 1, "hello world" };
std::cout << std::get<0>(tuple) << '\n';
std::cout << std::get<1>(tuple) << '\n';
}

C++ function map with varialbles input

In C++, I want to use a map of functions with different type of input or output.
Do to so, I found that using a map with any type could be a way.
But I get several problems. First, I can not use directly the functions in the map.
However, I can use a lambda function to wrap the functions then use these lambda functions in the map.
But, I get a second problem, I still need to cast with the lambda function which is not a variable. This makes a use from a string variable complicated.
Here is a MWE:
#include <any>
#include <functional>
#include <iostream>
#include <map>
#include <string>
void funct0()
{
std::cout << "funct0" << std::endl;
}
void funct1(int p)
{
std::cout << "funct1 " << p << std::endl;
};
int funct2(int p, std::string s)
{
std::cout << "funct2 " << s << std::endl;
return p+1;
};
float funct3(int a, float b)
{
std::cout << "funct3 " << std::endl;
return a +b;
}
auto funct4(int a, float b)
{
std::cout << "funct4 " << std::endl;
std::vector<float> v;
v.push_back(a);
v.push_back(b);
return v;
}
int main()
{
std::map<std::string, std::any> mapFunct;
mapFunct["F0"]= funct0;
// mapFunct["FO"](); // error: no match for call to ‘(std::map<std::__cxx11::basic_string<char>, std::any>::mapped_type {aka std::any}) ()’
mapFunct["F1"]= funct1;
// mapFunct["F1"](12); // error: no match for call to ‘(std::map<std::__cxx11::basic_string<char>, std::any>::mapped_type {aka std::any}) (int)’
// WHY THIS IS NOT WORKING ?
// From this link: https://stackoverflow.com/questions/61969316/is-it-possible-to-put-lambda-expressions-into-a-map-or-list-in-c
auto lambda0 = [](){funct0();};
auto lambda1 = [](int p) { funct1(p); return p; };
auto lambda2 = [](int p, std::string s) { return funct2(p,s); };
auto lambda3 = [](int a, float b){return funct3(a,b);};
auto lambda4 = [](int a, float b){return funct4(a,b);};
std::map<std::string, std::any> mapLambda;
mapLambda["L0"]=lambda0;
mapLambda["L1"]=lambda1;
mapLambda["L2"]=lambda2;
mapLambda["L3"]=lambda3;
mapLambda["L4"]=lambda4;
std::any_cast<decltype(lambda0)>(mapLambda["L0"])();
std::any_cast<decltype(lambda1)>(mapLambda["L1"])(2);
std::cout << std::any_cast<decltype(lambda2)>(mapLambda["L2"])(4, "HELLO") << std::endl;
std::cout << std::any_cast<decltype(lambda3)>(mapLambda["L3"])(3, 4.32) << std::endl ;
auto vec4= std::any_cast<decltype(lambda4)>(mapLambda["L4"])(6, 9.1);
std::cout << "vec4" << vec4[1] << vec4[2] << std::endl ;
std::vector<std::string> inputString;
inputString.push_back("L3(3, 4.32)");
inputString.push_back("L4(6, 9.1)");
// Using a for loop with iterator
for(auto it = std::begin(inputString); it != std::end(inputString); ++it) {
std::cout << *it << "\n";
std::string line=*it;
std::string functionInput = line.substr( 0, line.find("(") );
std::cout << functionInput << std::endl;
// argumentsInput= ;
mapLambda[functionInput](argumentsInput);
}
};
So my question are:
Why my example is working with lambda functions and not the functions ?
How can I make the last part of my example works only from the inputString variable? (ie, knowing the correct casting from the string variable)
What you probably want is something like this:
using CallWrapper = std::function<void(const std::string&)>;
std::map<std::string, CallWrapper> mapLambda;
mapLambda["L0"] = [funct0](const std::string&) { funct0(); };
mapLambda["L1"] = [funct1](const std::string& args) {
int p = ...; // parse the argument from `args`
funct1(p);
};
mapLambda["L2"] = [funct2](const std::string& args) {
// parse the arguments from `args`
int p = ...;
std::string s = ...;
funct2(p, s);
};
Now you can run the loop you envision:
for(const std::string& line : inputString) {
size_t pos = line.find('(');
std::string functionInput = line.substr( 0, pos);
std::string argumentsInput = line.substr(pos);
mapLambda[functionInput](argumentsInput);
}
The hard part, of course, is "parse the arguments from args", left as an exercise for the reader.
std::any_cast needs to cast to constructible types. A standard C++ function is neither a type nor constructible (it's just a group of statements given a name [edit: this isn't technically true, but what's going on under the hood is fairly complicated]), but std::function is. One way to get around this is to assign a standard C++ function to an std::function. Here's an example using a std::map like you were using:
#include <any>
#include <functional>
#include <iostream>
#include <map>
int my_func(int val) { return val + 1; }
std::function<int(int)> f = my_func;
int main() {
auto my_map = std::map<std::string, std::any>();
my_map["func"] = f;
std::cout << std::any_cast<std::function<int(int)>>(my_map["func"])(13) << std::endl; // prints "14"
return 0;
}
Lambdas are constructible types, which is why your code works for lambdas.
To answer your second question: I don't think it's possible. Functions with different signatures are different types, and you have to know what you're casting to. std::function<int(int, string)> and std::function<float(int, float)>, for example, are different types.
Also, the intended purpose of lambdas is to be used once then discarded. If you're going to keep lambdas around for reuse, it's better to simply just use functions.

Is it possible to put lambda expressions into a map or list in C++?

#DanielLangr #luxun #cdhowie sorry for the XY problem. i am not sure i can explain well, but i try my best. the situation is almost like this: there is a base object "Worker" and some children. chef、tailor... children has the same action like walk、run、sleep...but different skill,chef can make food, tailor can Make clothes. Invoker call Worker dothings but do not exactly know their profession.so i add a interface dothings(Thing) on Worker the base object. Thing is an enum,value is MakeFood、MakeClothes...
Worker *w = new Chef();
w->dothings(MakeFood);//
w->dothings(MakeClothes);//throw exception "w do not have skill"
so i think meybe use a container in children that describe what it can do and how to do.
hope i explained clearly.and is there a better solution?
I want to put different lambda expressions into a list or Qmap, like below.
Qmap<String, lambda> map;
map.insert("first",[](int i) -> int {return i;});
map.insert("second",[](string s) -> string {return s;});
Is it possible in C++? And what is the type of lambda?
It is possible but using function wrapper.
For example,
std::map<std::string, std::function<void(std::string)>> my_map;
my_map.emplace("first", [](std::string i) { std::cout << i << std::endl; });
However, if you want to pass any type of argument to your function and return any type from your lambda/function, use boost::any. You also use std::any if you are using C++17 or above.
EDIT:
A working example:
#include <iostream>
#include <string>
#include <functional>
#include <map>
#include <boost/any.hpp>
int main()
{
auto any = [](boost::any i)
{
std::cout << "In any" << std::endl;
if (i.type() == typeid(int))
std::cout << boost::any_cast<int>(i) << std::endl;
return boost::any(1000);
};
std::map<std::string, std::function<boost::any(boost::any)>> my_map;
my_map.emplace("first", any);
my_map.emplace("second", [](boost::any i) -> boost::any { });
auto ret = my_map["first"](100);
std::cout << boost::any_cast<int>(ret) << std::endl;
return 0;
}
Outputs:
In any
100
1000
With any, the solution may look like as follows:
auto lambda1 = [](int i) { return i; };
auto lambda2 = [](std::string s) { return s; };
std::map<std::string, std::any> map;
map["first"] = lambda1;
map["second"] = lambda2;
std::cout << std::any_cast<decltype(lambda1)>(map["first"])(-1) << std::endl;
std::cout << std::any_cast<decltype(lambda2)>(map["second"])("hello") << std::endl;
I am not familiar with Qmap and String, so I used the types from the C++ Standard Library.
Live demo: https://godbolt.org/z/8XK8de
Alternatively, you can also additionally use std::function if you want to avoid those decltypes:
std::map<std::string, std::any> map;
map["first"] = std::function<int(int)>( [](int i) { return i; } );
map["second"] = std::function<std::string(std::string)>( [](std::string s) { return s; } );
std::cout << std::any_cast<std::function<int(int)>>(map["first"])(-1) << std::endl;
std::cout << std::any_cast<std::function<std::string(std::string)>>(map["second"])("hello") << std::endl
Live demo: https://godbolt.org/z/XAc3Q2
However, as other pointed out to, this really seems to be an XY problem.
It is possible as long as you are trying to insert the same lambda type ( your example has different lambda types) You have to be careful how you do it but it does work. For example
#include <iostream>
#include <map>
int main(){
auto factory = [](int i){
return [=](int j){return i+j;};
};
using L = decltype(factory(0));
std::map<int,L> map;
map.emplace(0,factory(0));
map.emplace(7,factory(7));
std::cout << map.at(0)(3) << std::endl ;
std::cout << map.at(7)(3) << std::endl ;
}
outputs
3
10
as expected and not a std::function in sight! However the following does not work
#include <iostream>
#include <map>
int main(){
auto factory = [](int i){
return [=](int j){return i+j;};
};
using L = decltype(factory(0));
std::map<int,L> map;
map[0]=factory(0);
map[7]=factory(7);
std::cout << map[0](3) << std::endl ;
std::cout << map[7](3) << std::endl ;
}
Using the indexing operator tries to use copy assignment whereas emplace doesn't.
https://godbolt.org/z/co1vno6xb

Convert from pointer-to-member template function to functional type objects

I have this code that works already:
// mem_fun example
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <map>
using namespace std;
struct C
{
C(int i): y_(i) {};
int y_;
string op1(int x)
{
std::ostringstream oss;
oss << "operation 1: " << x+y_;
return oss.str();
}
string op2(string x)
{
std::ostringstream oss;
oss << "operation 2: " << x << "+" << y_;
return oss.str();
}
};
struct container: map<string, C>
{
// doesn't compile
// void safeOperation(string key, ??? bound_function_and_arg_object )
template< typename argType >
void safeOperation(string key, string (C::*mf)(argType a), argType a)
{
iterator it = find(key);
if (it != end())
{
C* pC = &(it->second);
cout << (pC->*mf)(a) << "\n";
}
else
{
cout << "key: " << key << " missing\n";
}
}
};
int main () {
container objects;
objects.insert(container::value_type("a1", C(1)));
objects.insert(container::value_type("b2", C(2)));
objects.insert(container::value_type("c3", C(3)));
objects.safeOperation("a1", &C::op1, 1);
objects.safeOperation("b2", &C::op1, 2);
objects.safeOperation("d4", &C::op1, 4);
objects.safeOperation("c3", &C::op2, string("3"));
return 0;
}
I'd like to change the template function on the map to use std::mem_fun and to bind the parameters together with the operation, rather than specify them as separate parameters to safeOperation.
In other words, I'd prefer to call safeOperation similar to this:
// wrong, but hopefully communicates what I'm trying to do:
objects.safeOperation(someKey, bind(&C::op1, 4));
The sample code is here: http://cpp.sh/74pgb
I'm probably missing something simple, but appreciate the help.
When you bind a member function, the first argument has to be an instance of the class whose member function it is. So what you want to do is generalize safeOperation to take any function that can be called on a C*:
template< typename F >
void safeOperation(string key, F func) {
iterator it = find(key);
if (it != end())
{
C* pC = &(it->second);
cout << func(pC) << "\n";
}
else
{
cout << "key: " << key << " missing\n";
}
}
And then generate your funcs by binding with the argument, but also leaving a placeholder:
using namespace std:;placeholders;
objects.safeOperation("a1", std::bind(&C::op1, _1, 1));
// ^^
// placeholder for pC
boost/std::bind create an object with an implementation-specific type. The only requirement is that the object is callable using operator().
To handle any functional objects you can change your function template in the following way:
template< typename F >
void safeOperation(string key, F f)
{
// ...
cout << f(pC) << "\n";
// ...
objects.safeOperation("someKey", bind(&C::op1, placeholders::_1, 4));
That should enable almost the syntax you require.

Sort std::vector<myclass> in one line using sort function from STL

Question is about sorting std::vector<myclass> using function sort from STL's algorithms class.
Standard way is : sort(v.begin(), v.end(), &myfunct)
where myfunct is:
bool myfunct( myclass first, myclass second ) {
if (first.value < second.value)
return true;
else return false;
}
Approach above takes more than one line. I am curious how to do it in one line. Is it possible define function that compares myclass objects inside sort function? May be somehow use this (a < b) ? a : b. I remember that there is something like this in C#, but I forgot how is it called. Is it possible to do in C++.
First, you can just return first.value < second.value but this doesn't get rid of the function. In C++2011 you can use a lambda function:
std::sort(begin, end, [](myclass const& f, myclass const& s){ return f.value < s.value; });
Without C++2011 I think you'll need a function object because there isn't anything which projects your class to the value you actually want to compare.
BTW, you definitely want to pass everything but the most trivial objects by reference to your comparison function.
You could use boost::lambda and boost::lambda::bind (with boost lambda placeholders)
std::sort(vec.begin(), vec.end(),
boost::lambda::bind(&A::a, boost::lambda::_1)
<
boost::lambda::bind(&A::a, boost::lambda::_2));
sort passes 2 values to the comparison function so you need to compare those 2 values. The bind part of code just selects variable a from the struct A from each structures being compared (referenced by _1 and _2).
Example code:
#include <iostream>
#include <algorithm>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/array.hpp>
struct A
{
A() : a(0), b(0) {}
int a;
int b;
};
std::ostream & operator<<(std::ostream & os, A & a)
{ return os << a.a << ":" << a.b; }
int main()
{
boost::array<A,5> vec;
std::fill(vec.begin(),vec.end(),A());
vec[0].a = 1;
vec[1].a = 3;
vec[2].a = 4;
vec[3].a = 0;
vec[4].a = 2;
std::for_each(vec.begin(),vec.end(), std::cout << boost::lambda::_1 << ' ');
std::cout << std::endl;
std::sort(vec.begin(), vec.end(),
boost::lambda::bind(&A::a, boost::lambda::_1)
<
boost::lambda::bind(&A::a, boost::lambda::_2));
std::for_each(vec.begin(),vec.end(), std::cout << boost::lambda::_1 << ' ');
std::cout << std::endl;
}
Output:
1:0 3:0 4:0 0:0 2:0
0:0 1:0 2:0 3:0 4:0
why not copy the vector into a set:
std::copy(v.begin(),v.end(),std::inserter(s,s.end()));
Now the elements in the set are sorted in ascending order and use set now.
A one liner call to sort() : sort(my_vector_of_class_object.begin(),my_vector_of_class_object.end(),compare);
Code of a working demo of a "sort vector of class objects" is provided below:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class my_Class
{
public:
my_Class(int r,int n, int s):rollno(r),name(n),status(s) { }
int getRollno() const { return rollno;}
int getName() const { return name;}
int getStatus() const { return status;}
private:
int rollno;
int name;
int status;
};
bool compare(const my_Class& x, const my_Class& y) {
return x.getRollno() < y.getRollno();
}
int main()
{
vector<my_Class> my_vector_of_class_object;
vector<my_Class>::const_iterator iter;
my_Class s1(10,20,30);
my_Class s2(40,50,60);
my_Class s3(25,85,9);
my_Class s4(1,50,2);
my_Class s5(90,70,90);
my_Class s6(85,85,3);
my_Class s7(20,6,89);
my_Class s8(70,54,22);
my_Class s9(65,22,77);
my_vector_of_class_object.push_back(s1);
my_vector_of_class_object.push_back(s2);
my_vector_of_class_object.push_back(s3);
my_vector_of_class_object.push_back(s4);
my_vector_of_class_object.push_back(s5);
my_vector_of_class_object.push_back(s6);
my_vector_of_class_object.push_back(s7);
my_vector_of_class_object.push_back(s8);
my_vector_of_class_object.push_back(s9);
cout <<"Before vector sort \n";
for(iter=my_vector_of_class_object.begin(); iter!=my_vector_of_class_object.end();++iter)
std::cout << (*iter).getRollno() << '\t' << (*iter).getName() << '\t' << (*iter).getStatus() << '\n';
cout <<" \n\n";
sort(my_vector_of_class_object.begin(),my_vector_of_class_object.end(),compare);
cout <<"After vector sort \n";
for(iter=my_vector_of_class_object.begin(); iter!=my_vector_of_class_object.end();++iter)
std::cout << (*iter).getRollno() << '\t' << (*iter).getName() << '\t' << (*iter).getStatus() << '\n';
cout <<" \n\n";
return 0;
}