I have a large series of functions that all look very similar: they take the same arguement type and return strings.
std::string f1(T arg);
std::string f2(T arg);
std::string f3(T arg);
std::string f4(T arg);
.
.
.
In a loop, they are used according to one of the variables inside the struct T. Currently to do this, I just have a large switch/case block in my code.
Is there any better coding style for doing this? The large block of code looks very weird.
I wish c++ could be like python and do eval("f" + str(i) + "(arg))"
The block is something like this:
std::string out = "";
switch (arg.tag){
case 1:
out += f1(arg);
break;
case 2:
out += f2(arg);
break;
.
.
.
}
for about 2 dozen cases
With C++11 you can do this fairly easily with std::function and a map:
#include <map>
#include <functional>
#include <string>
#include <iostream>
std::string f1(int) { return "f1"; }
std::string f2(int) { return "f2"; }
std::map<int, std::function<std::string(int)> > funcs = {
{1,f1},
{2,f2}
};
int main() {
std::cout << funcs[1](100) << "\n";
}
Without C++11 you'll want to either use Boost instead of std::function or roll your own type instead. You could use plain old function pointers but that would rule out some handy things (like std::bind/boost::bind, functor objects, lambda functions. You could also define a type hierarchy with an interface that your functions implement for example the following works in C++03 except for the way the map is initialised:
#include <map>
#include <functional>
#include <string>
#include <iostream>
std::string f1(int) { return "f1"; }
std::string f2(int) { return "f2"; }
std::map<int, std::string(*)(int)> funcs = {
std::make_pair(1,f1),
std::make_pair(2,f2)
};
int main() {
std::cout << funcs[1](100) << "\n";
}
or this which lets you write any kind of functor object you like:
#include <map>
#include <string>
#include <iostream>
struct thing {
virtual std::string operator()(int) const = 0;
};
struct f1 : thing {
std::string operator()(int) const { return "f1"; }
};
struct f2 : thing {
std::string operator()(int) const { return "f2"; }
};
// Note the leak - these never get deleted:
std::map<int, thing*> funcs = {
std::make_pair(1,new f1),
std::make_pair(2,new f2)
};
int main() {
std::cout << (*funcs[1])(100) << "\n";
}
One way to emulate the Eval() is to have a map. The key of the map would be the names of the functions, and the values would be the pointers to the corresponding functions.
In this case you will be able to call the functions needed with the map's operator[] by their name. This will somehow emulate the eval("f" + str(i) + "(arg))" behavior, though it may still not be the best solution for you.
Related
I have a class that has a constructor. I now need to make a map with it as a value how do I do this? Right now without a constructor I do.
#include <iostream>
#include <map>
using namespace std;
class testclass {
public:
int x = 1;
};
int main()
{
map<int,testclass> thismap;
testclass &x = thismap[2];
}
If I added a constructor with arguments how would I add them to the map? I basically need to do
#include <iostream>
#include <map>
using namespace std;
class testclass {
public:
int x = 1;
testclass(int arg) {
x = arg;
}
};
int main()
{
map<int,testclass> thismap;
testclass &x = thismap[2];
}
This obviously wouldn't work since it requires an argument but I can't figure a way of doing this.
This is how you can add items of your own class to your map.
Note : I used a string in testclass to better show difference
between key and value/class.
#include <iostream>
#include <string>
#include <map>
class testclass
{
public:
explicit testclass(const std::string& name) :
m_name{ name }
{
};
const std::string& name() const
{
return m_name;
}
private:
std::string m_name;
};
int main()
{
std::map<int, testclass> mymap;
// emplace will call constructor of testclass with "one", and "two"
// and efficiently place the newly constructed object in the map
mymap.emplace(1, "one");
mymap.emplace(2, "two");
std::cout << mymap.at(1).name() << std::endl;
std::cout << mymap.at(2).name() << std::endl;
}
Using std::map::operator[] requires that the mapped type is default-constructible, since it must be able to construct an element if one doesn't already exist.
If your mapped type is not default-constructible, you can add elements with std::map::emplace, but you still can't use std::map::operator[] to search, you will need to use std::map::find() or so.
That's a rather obvious feature of std::map (and very similar other std containers). Some of their operations require specific type requirements for good reasons.
There is no problem to create such a map as you suggest in the first place, however, you are restricted to method calls that do not require potential default construction. The operator[] is such a method, since in the case the element is not found, it is created. That is what does not work in your example. Just use other methods with little impact on the map usage and you can still succeed:
#include <iostream>
#include <map>
using namespace std;
class testclass {
public:
int x = 1;
testclass(int arg) {
x = arg;
}
};
int main()
{
map<int,testclass> thismap;
thismap.insert( {2, testclass(5)} );
auto element2 = thismap.find(2);
if (element2 != thismap.end()) {
testclass& thiselement = element2->second;
cout << "element 2 found in map, value=" << thiselement.x << endl;
}
auto element5 = thismap.find(5);
if (element5 == thismap.end()) {
cout << "no element with key 5 in thismap. Error handling." << endl;
}
}
Main issue: avoid operator[].
Note:
Looking at the other very good answers, there are a lot of methods that can be used without default construction. There is not "right" or "wrong" since this simply depends on your application. at and emplace are prime examples that are highly advisable.
I'm new to C++ and very confused on how to approach this. In Javascript, I can do something like this to access an object dynamically very easily:
function someItem(prop) {
const item = {
prop1: 'hey',
prop2: 'hello'
};
return item[prop];
}
In C++, I'm assuming I have to use a Struct, but after that I'm stuck on how to access the struct member variables dynamically.
void SomeItem(Property Prop)
{
struct Item
{
Proper Prop1;
Proper Prop2;
};
// Item[Prop] ??
}
This could be terrible code but I'm very confused on how to approach this.
This is a simple example of how to create an instance of a struct and then access its members:
#include <iostream>
#include <string>
struct Item {
std::string prop1 = "hey";
std::string prop2 = "hello";
};
int main() {
Item myItem;
std::cout << myItem.prop1 << std::endl; // This prints "hey"
std::cout << myItem.prop2 << std::endl; // This prints "hello"
return 0;
}
As mentioned in the comments, it looks like you might want a map. A map has keys and values associated with them, as an example you could have a key "prop1" be associated with a value "hey":
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::string> myMap;
myMap["prop1"] = "hey";
myMap["prop2"] = "hello";
std::cout << myMap["prop1"] << std::endl; // This print "hey"
std::cout << myMap["prop2"] << std::endl; // This print "hello"
return 0;
}
The first would be considered "normal" struct usage in C++ and the other is more applicable to cases where you have to look things up by keys
As mentioned in a comment, in C++ you would not define a custom structure for this, but rather use a std::unordered_map. I don't know Javascript, though if Property is an enum (it could be something else with small modifications) and return item[prop]; is supposed to return a string, then this might be close:
#include <string>
#include <unordered_map>
#include <iostream>
enum class Property { prop1,prop2};
std::string someItem(Property p){
const std::unordered_map<Property,std::string> item{
{Property::prop1,"hey"},
{Property::prop2,"hello"}
};
auto it = item.find(p);
if (it == item.end()) throw "unknown prop";
return it->second;
}
int main(){
std::cout << someItem(Property::prop1);
}
std::unordered_map does have a operator[] that you could use like so return item[p];, but it inserts an element into the map when none is found for the given key. This is not always desirable, and not possible when the map is const.
Consider this example:
#include <vector>
#include <string>
#include <functional>
#include <iostream>
using closure_type = std::function<void(void)>;
using closure_vec = std::vector<closure_type>;
class callbacks {
static closure_type common(std::string name, uint32_t number) {
return [number, name]() { std::cout << name << number << std::endl; };
}
public:
static closure_type foo(uint32_t number) { return common("foo ", number); }
static closure_type print(std::string msg) {
return [msg]() { std::cout << "print " << msg << std::endl; };
}
};
template <typename... calls_t> closure_vec wrap(uint32_t number, calls_t &&... calls) {
return closure_vec {
callbacks::foo(number),
std::forward<calls_t>(calls)...,
};
}
int main() {
auto vec = wrap(42,
callbacks::print("hello, "),
callbacks::print("world"));
for(auto &e: vec)
e();
return 0;
}
Demo (On the right most tab there is a full message)
When this code is checked with clang-tidy, I get the following warning:
warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
The line number points at the scope exit of the wrap function.
As I understand the message, the tool is concerned that the results form callbacks::foo might be lost. But I don not understand how is it possible: std::function is a safe class and should destroy everything nicely in its destructor. Also its lifetime is controlled by the vector which is safe too.
What is going on here? How do I fix this or workaround?
Unfortunately I cannot just suppress the warning, as this code is scattered everywhere in the codebase.
Try
closure_vec retval;
retval.reserve(sizeof...(calls)+1);
retval.push_back(callbacks::foo(number));
( retval.push_back(std::forward<calls_t>(calls)), ... );
return retval;
this avoids the const initializer_list contained copies of std function your code created, so should be more efficient as well.
Live example.
I tried using a C style array here, but I got the warning as well despite not using a std::initializer_list.
This also works:
std::array<closure_type, sizeof...(calls)+1> tmp ={
nullptr,
std::forward<calls_t>(calls)...
};
tmp[0] = callbacks::foo(number);
return {std::make_move_iterator(std::begin(tmp)), std::make_move_iterator(std::end(tmp))};
the problem is callbacks::foo(number) within the initalization.
I want my function to return a string, but only strings which are a member of a specific list/set of strings. How can I go about doing this?
You do not want to return a string, you want to return a string that has an additional restriction (being part of some predefined set).
For that you'd need a new type:
class BusinessStringWrapper {
public:
BusinessStringWrapper(std::string arg): value{arg} {
if (/* arg is not ok */) {
throw;
}
}
// you can replace that with factory method
// can also return std::optional instead of throwing if the condition is not met
// that depends on your application
std::string value() const { return value; }
private:
const std::string value;
};
And in your application you'd operate on this type, accessing value if needed.
Hoe about using a std::set<std::string>?
#include <iostream>
#include <set>
#include <string>
std::string helper(const std::string & str,
const std::set<std::string> & lst)
{
return lst.find(str) == lst.end() ? "" : str;
}
int main()
{
std::set<std::string> lst = {"alpha", "beta", "gamma"};
std::cout << "return " << helper("alpha", lst) << "\n";
std::cout << "return " << helper("zeta", lst) << "\n";
return 0;
}
Output
return alpha
return
Of course, it really depends on what your definition of does not return is.
If it means an empty string, then use the above solution. Keep your life simple.
If it means an error and the program should terminate, you may #include <cassert> and just
assert(lst.find(str) != lst.end());
If it means an exception to handle, you may try throw and catch.
If it means returning a std::string if str is in a predefined list, but a void if it's not, then you may need some tricks as described in <type_traits>.
You can do this std::map<CardType, std::string> in the example below, or use std::map<int, std::string> to associate a string with any integer. For example mp[123]="abcd"
#include <iostream>
#include <string>
#include <map>
enum CardType {
SPADE,
HEART,
CLUBS,
DIAMD
};
std::map<CardType, std::string> mp{
{CardType::SPADE, "Spade"},
{CardType::HEART, "Heart"},
{CardType::CLUBS, "Clubs"},
{CardType::DIAMD, "Diamond"}
};
int main()
{
std::cout << mp[CardType::SPADE] << std::endl;
return 0;
}
Firstly,I want to inform you that my overall/main target is to execute certain functions using their function name(string) as an argument,I defined a function as below:
(I want to generate a unique number for each string data that I inserted as argument to a function)
#include <iostream>
#include <string>
#include <hash_set>
using namespace std;
void Func_Execution(string &s){
int k=stdext::hash_value(s);
#if(_MSC_VER ==1500)
switch (k)
{
case -336300864: GETBATTERYCALLSIGNS();
break;
case -1859542241:GETGUNIDS();
break;
case 323320073:Foo(); // here int k=323320073 for string s="Foo"
break;
case 478877555:Bar();
break;
defalut :Exit();
break;
}
#endif
}
Here I call Func_Execution function as below:
void main(){
string s="Foo";
Func_Execution(s);
}
I want to know that is there any efficient(considering perfomance/time consuming) and effective mechanism to generate a unique numerical value for certain string(character pattern) rather than using stdext::hash_value() function?(Also notice I want to implement switch-case too)
Have you considered something like
#include <functional>
#include <iostream>
#include <unordered_map>
#include <string>
using std::cout;
using std::endl;
using std::function;
using std::string;
using std::unordered_map;
class Registry {
public:
static void Execute(const string& function) {
if (functions_.find(function) != functions_.end()) {
functions_[function]();
}
}
static int Register(const string& function_name, function<void()> f) {
functions_.emplace(function_name, f);
return functions_.size();
}
static void Dump() {
for (auto& i : functions_) {
cout << i.first << endl;
}
}
private:
Registry() {};
static unordered_map<string, function<void()>> functions_;
};
unordered_map<string, function<void()>> Registry::functions_;
#define REGISTER_FUNCTION(F) \
namespace { \
const int REGISTERED__##F = Registry::Register(#F, &F); \
}
void foo() {
cout << "foo" << endl;
}
REGISTER_FUNCTION(foo);
void bar() {
cout << "bar" << endl;
}
REGISTER_FUNCTION(bar);
int main() {
Registry::Execute("foo");
Registry::Execute("foo");
Registry::Execute("unknown");
Registry::Dump();
return 0;
}
It should serve well for your use case. I just hacked it together, there's probably a bug somewhere, but it compiles and runs (c++11).
Don't use hash_value() for fingerprinting (which is what you are describing). If you really know all your possible strings ahead of time, use your own perfect hash function and then measure the results to see if it is worth it.