I studied enums which expects only integer inputs and returns corresponding value to it.I want to achieve same thing but I only have strings as a input. I want to make following work -
enum Types {
"Absolute", //"abs"
"PURE", //"PRE"
"MIXED" //"MXD"
}
and probable statment could be -
string sTpes = Types("abs"); //this should return "Absolute"
or
string sTpes = Types("MXD"); //this should return "MIXED"
If not using enums, please suggest me possible ways to achieve this.
Thanks.
There are no "string-enums", but to map from one value to another, you can use std::map, which is a standard template shipped with C++ platforms:
#include <map>
#include <string>
int main() {
using std::map; using std::string;
map<string, string> ss;
ss["abs"] = "Absolute";
const string foo = ss["abs"];
std::cout << ss["abs"] << ", or " << foo << std::endl;
}
In C++0x, if you want "safe" access that throws an exception if the key-type wasn't found, use map::at (actually, afair, the lack of map::at was just an oversight in the current standard):
std::cout << ss.at("weird keY");
or check if it exists:
if (ss.find("weird keY")==ss.end())
std::cout << "key not found\n";
if you are talking about c++/cli you could use this
Hashtable^ openWith = gcnew Hashtable();
// Add some elements to the hash table. There are no
// duplicate keys, but some of the values are duplicates.
openWith->Add("txt", "notepad.exe");
openWith->Add("bmp", "paint.exe");
openWith->Add("dib", "paint.exe");
openWith->Add("rtf", "wordpad.exe");
from http://msdn.microsoft.com/fr-fr/library/system.collections.hashtable.aspx#Y4406
else use map from stdlib.
I think you can also use CMAP from MFC, there is a good article about it here : http://www.codeproject.com/KB/architecture/cmap_howto.aspx
An enum has an integral value. Personally I simply suggest two conversion functions:
enum -> string
string -> enum
The first can be implemented with a simple array, the second require a binary search in a sorted list.
you could use a string array (of size 2) from string.h i think (either that or just string; one is for C and other is for cpp). first string is "abs" second is "absolute".
for example:
#include <string>
...
string abs[2]; //or a better name that's more relevant to you
abs[0] = "abs";
abs[1] = "absolute";
...
//pass it into the function
cout << abs[1] << endl;
...
Related
I want to have an input to a function similar to python so that then I can loop over it in inside the function. But I am not sure how I should define the input.
func(["a","b","c"])
so that it can also be called
func(["a","b","c", "d"])
is there actually such style of input in c++?
I'd be glad if someone also suggested a way of looping over it since my c++ experience is quite basic.
-------edit,
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Yes, you can use std::initializer_list to do that:
#include <initializer_list>
template<class T>
void func(std::initializer_list<T> il) {
for (auto x : il);
}
int main() {
func({"a","b","c"});
func({"a","b","c", "d"});
}
will be glad if this "[]" style of brackets are possible instead of
"{}" similar to python and with minimal code.
Unfortunately, the multidimensional subscript operator only works in C++23, see p2128 for more details.
You can use a std::initilializer_list:
#include <iostream>
#include <initializer_list>
void foo(std::initializer_list<std::string> l){
for (const auto& s : l) std::cout << s << " ";
}
int main() {
foo({"a","b","c"});
}
I think python does not distinguish between character and string literals, but C++ does. "a" is a string literal, while 'a' is a character literal. If you actually wanted characters you can use a std::initializer_list<char>. You can also consider to simply pass a std::string to the function (foo("abc")).
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Better get used to different languages being different. Trying to make code in one language look like a different language usually does not pay off, because not only in details python and C++ are very different.
The other answers will work but I think your looking for std::vector, which is a array that can dynamically grow and shrink. It is basically the c++ equivalent to a python list (except you can only store on data type in it).
#include <iostream>
#include <vector>
void foo (std::vector<std::string> vec)
{
// normal for loop
for (int i = 0; i < vec.size (); i++)
{
std::cout << vec[i] << std::endl; // do something
}
std::cout << "#########" << std::endl;
// range based for loop
for (auto val : vec)
{
std::cout << val << std::endl;
}
std::cout << "#########" << std::endl;
}
int main ()
{
foo ({'a', 'b', 'c'});
foo ({'a', 'b', 'c', 'd'});
}
replace std::string with the data type that you need.
live example
I would recommend you to use std::initializer_list for that purpose.
The function may be defined as follows:
void func(std::initializer_list<std::string> il)
{
for(const std::string & s : il)
{
// ...
}
}
And you may use it the following way:
int main()
{
func({"a", "b", "c"});
return 0;
}
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Python and C++ are not the same languages and symbols, keywords, etc... have their own meaning. In Python, [] means a list, but in C++ it is the subscript operator (supposed to be called for a given object), which is a completely different thing.
I have the following
The two equivalent strings bar and bartest do not map to the same value in unordered_map. How can I make this happen?
Of course they don't map to the same value, const string* is a pointer type and since you call new string twice, you end up with two separate objects that don't have memory identity (the pointers are not equal).
What's worse, you leak both of them at the end of your program.
What's (arguably) worse still, owning raw pointers and naked new calls are considered harmful in modern c++.
Luckily it's all fixed with unordered_map<string, int> - no pointers required whatsoever.
Your C++ is in fact "Java-- + C".
Remove all those silly pointers.
All you need is unordered_map<string,int> and use plain values instead of heap-allocated "news"
just do
#include <unordered_map>
#inclide <string>
#include <iostream>
int main()
{
unordered_map<string,int> mymap;
mymap["bar"] = 5;
mymap["bartest"] = 10;
std::cout << mymap["bar"] << ' ' << mymap["bartest"] << '\n';
return 0;
}
I need to call boost::trim_left_if on a single char value:
// pseudo code; not tested.
std::string to_trim{"hello"};
char left_char = 'h';
boost::algorithm::trim_left_if(to_trim, /*left_char?*/);
In the last line above, I need a way to pass in the char value. I looked around but I didn't see a generic predicate in Boost or STL to simply compare two arbitrary values. I could use lambdas for this but would prefer the predicate, if one exists.
One thing I want to avoid here is using boost::is_any_of() or any other predicates that would require left_char to be converted to a string.
Since C++11, the idiomatic way to compare for equality to a fixed value is to use a bind-expression with std::equal_to:
boost::algorithm::trim_left_if(to_trim,
std::bind(std::equal_to<>{}, left_char, std::placeholders::_1));
This uses the transparent predicate std::equal_to<void> (since C++14); in C++11 use std::equal_to<char>.
Prior to C++11 (and, likely, until C++17) you can use std::bind1st in place of std::bind and std::placeholders::_1.
Remaining within Boost, you could also use boost::algorithm::is_any_of with a unitary range; I find boost::assign::list_of works well:
boost::algorithm::trim_left_if(to_trim,
boost::algorithm::is_any_of(boost::assign::list_of(left_char)));
Why not just write one?
#include <iostream>
#include <boost/algorithm/string/trim.hpp>
struct Pred
{
Pred(char ch) : ch_(ch) {}
bool operator () ( char c ) const { return ch_ == c; }
char ch_;
};
int main ()
{
std::string to_trim{"hello"};
char left_char = 'h';
boost::algorithm::trim_left_if(to_trim, Pred(left_char));
std::cout << to_trim << std::endl;
}
Seriously - the stuff in boost is not "sent down from on high", it's written by people like you and me.
Let's say I have different types of components which are structs. Maybe I have TransformComponent and RigidBodyComponent
Now, this is the problem: I want something like an std::map where you map a component type and an id to a component. The ids are what links components together. What kind of container should I use for this? I can't use an std::map<std::typeindex, std::map<id_t, T>> since the type T depends on which typeindex you use to index the first map.
Your use case sounds like a typical use of polymorphism. You should know that any attempts to store "non-homogenous" types in a single container will come with the performance penalty of polymorphism. As of whether you will use "out of the box" polymorphism that C++ provides or go for a custom solution - its entirely up to you.
BTW, to cite one of the questions from the comments on the question:
Suppose you can have such a container. What will you do with it? Can
you show some intended usage examples?
This is a very good question, because revealing your particular usage scenario will allow other to answer your question in much more detail, because right now it sounds like you don't really know what you are doing or need to do. So, if you need further guidance, you should really clarify and build on your question.
If you need to work with container which contain different types, look on some BOOST libraries:
Any: Safe, generic container for single values of different value types. (http://www.boost.org/doc/libs/1_54_0/doc/html/any.html)
Variant: Safe, generic, stack-based discriminated union container (http://www.boost.org/doc/libs/1_54_0/doc/html/variant.html)
Use variant, if list of your types is well defined and does not change.
So your code can look like this:
typedef boost::variant<TransformComponent, RigidBodyComponent> my_struct;
std::map<std::typeindex, std::map<id_t, my_struct> > cont;
...
std::typeindex index = std::type_index(typeid(TransformComponent));
std::map<id_t, my_struct> & m = cont[index];
id_t id = ...;
TransformComponent & component = boost::get<TransformComponent>(m[id]);
This code is quite ugly, so think about changing architecture. May be it will simpler with boost::any or with boost::variant.
P.S.
If you write template code then may be better to look to boost::mpl.
So you can solve this if you don't mind writing a custom container that uses ye olde C hacking.
I've written you an example here:
#include <iostream>
using namespace std;
struct ent
{
int myInt;
};
struct floats
{
float float1;
float float2;
};
struct container
{
bool isTypeFloats;
union
{
ent myEnt;
floats myFloats;
};
};
void main( void )
{
ent a = { 13 };
floats b = { 1.0f, 2.0f };
container c;
container d;
cout << b.float1 << " " << b.float2 << endl;
c.isTypeFloats = false;
c.myEnt = a;
d.isTypeFloats = true;
d.myFloats = b;
//correct accessor
if( c.isTypeFloats )
{
cout << c.myFloats.float1 << " " << c.myFloats.float2 << endl;
}
else
{
cout << c.myEnt.myInt << endl;
}
if( d.isTypeFloats )
{
cout << d.myFloats.float1 << " " << d.myFloats.float2 << endl;
}
else
{
cout << d.myEnt.myInt << endl;
}
}
To put these structs in a container you'd just do: std::vector< container >
A couple things you should know about this:
unions allocate space for the largest type. So in my example if an int takes 4 bytes and a float takes 4 bytes, then even when I'm storing just an ent it will allocate space for a floats so I'll be wasting 4 bytes each time I'm storing an ent. Depending on the purpose of your application and the size of the types you're storing this may be negligible.
If there is a significant disparity in size in the types you're storing then you can go about this the way C++ is really handling the union under the hood. And that's to use a void*. So you would do: std::vector< void* > myVec and you would insert like this: myVec.push_back( &x ) where x is your type, for example the ent from our example. But reading it out you'd have to know what you were pointing at so you'd have to know to do something like: cout << ( ( ent* )myVec[0] )->myInt << endl;
Because you probably wouldn't know what type it was unless you had some predefined writing pattern you'd probably just end up wanting to use a container struct like so:
struct container2
{
bool isTypeFloats;
void* myUnion;
}
How about boost::any or boost::any_cast ??
http://www.boost.org/doc/libs/1_54_0/doc/html/any.html
This prints the address for my string, but not its' contents,
#include <memory>
#include <string>
#include <list>
#include <iostream>
#include <iterator>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unique_ptr<list<shared_ptr<string>>> upList (new list<shared_ptr<string>>);
shared_ptr<string> spNation (new string ("India"));
upList->push_back (spNation);
copy (upList->begin(), upList->end(), ostream_iterator<shared_ptr<string>> (cout, "\n "));
return 0;
}
My questions are:
What ostream_iterator<shared_ptr<string>> is taking shared_ptr or strings as its' prime object.
How to print actual string contents (i.e. India) using this approach.
Is this approach is preferable over traditional for loop to print all node contents.
What ostream_iterator<shared_ptr<string>> is taking shared_ptr or strings as its' prime object.
You've instantiated ostream_iterator for shared_ptr<string>, so that is what it will attempt to output.
How to print actual string contents (i.e. India) using this approach.
If you really want to use shared pointers for some reason, then you can't use copy since that won't undo the extra level of indirection. Either use a plain loop, or get rid of the unnecessary indirection:
list<string> list;
list.push_back("India");
copy(list.begin(), list.end(), ostream_iterator<string>(cout, "\n "));
Of course, it doesn't look as exciting without all the arrows, templates, new-expressions and pseudohungarian warts, but anyone trying to maintain the code won't thank you for adding such embellishments.
Is this approach is preferable over traditional for loop to print all node contents
It's preferable when it makes the code simpler. When it doesn't, it isn't.
Firstly: why you use shared_ptr<string> instead of string here? You shouln't do this.
1)
shared_ptr<string>
2) Use std::for_each with lambda (or range-based for loop)
for_each(upList->begin(), upList->end(), [](const shared_ptr<string>& p)
{
cout << *p << endl;
});
or
for (const auto& p : upList)
{
std::cout << *p << std::endl;
}