std::ostream tellp() giving wrong output in VS2010 - c++

Below is the code i am running and corresponding output.
#include<iostream>
#include <sstream>
#include <strstream>
#include <streambuf>
template <typename char_type>
struct ostreambuf : public std::basic_streambuf<char_type,std::char_traits<char_type> >
{
ostreambuf(char_type* buffer, std::streamsize bufferLength)
{
// set the "put" pointer the start of the buffer and record it's length.
setp(buffer, buffer + bufferLength);
}
};
int main()
{
char strArr[] = "Before-1";
char stringArr[] = "Before-2";
std::strstream strStream(strArr,sizeof(strArr));
ostreambuf<char> ostreamBuffer(stringArr, sizeof(stringArr));
std::ostream stringStream(&ostreamBuffer);
const std::streampos posStringBefore = stringStream.tellp();
std::cout << "Before: "
<< "strArr = "
<< strArr
<< " & "
<< "stringArr = "
<< stringArr
<< std::endl;
std::cout << "Before: " << "posStringBefore = "
<< posStringBefore
<< std::endl;
// -------------------------
strStream << "After-1";
stringStream << "After-2";
const std::streampos posStringAfter = stringStream.tellp();
std::cout << "After : "
<< "strArr = "
<< strArr
<< " & "
<< "stringArr = "
<< stringArr
<< std::endl;
std::cout << "After : " << "posStringAfter = "
<< posStringAfter
<< std::endl;
return 0;
}
This is the o/p on VS2010 :
Before: strArr = Before-1 & stringArr = Before-2
Before: posStringBefore = -1
After : strArr = After-11 & stringArr = After-22
After : posStringAfter = -1
In reference to link
Setting the internal buffer used by a standard stream (pubsetbuf)
How to get the size of std::ostream object created?

It doesn't give you a "wrong" output/value. tellp uses rdbuf()->pubseekoff which relays the call to virtual seekoff. The basic_streambuf implementation simply returns -1 as defined in the C++ standard. You need to provide an own implementation for this method in your ostreambuf class.
See cppreference: basic_streambuf::pubseekof

Related

Reorder byte order for an array of 24-bit bytes using endian manipulations in arduino/c/c++?

I have a 24-bit array:
uint32_t rgbdata[] = { 0x00ff00 0xff0000 0x0000ff ...... }
Let's say the above data is in RGB order and I want GRB order
uint32_t grbdata[] = { 0xff0000 0x00ff00 0x0000ff ...... }
Without using loops, is there a quick endian manipulation way to do a certain byte order? Speed is of utmost importance in this case.
Here is a partial example of a uint24_t that you might port to your tools (I don't know the 'current' arduino's tool set)
// Note: compile with -std=c++17 for the using comma list
// or remove these and put the "std::" into code
#include <algorithm>
using std::swap;
#include <iostream>
using std::cout, std::cerr, std::endl, std::hex, std::dec, std::cin; // c++17
#include <string>
using std::string, std::to_string; // c++17
#include <sstream>
using std::stringstream;
class Uint24_t
{
public:
Uint24_t() : data {0,0,0}
{
cout << "\n sizeof(Uint24_t)= " << sizeof(Uint24_t) // reports 3 bytes
<< " bytes, * 8= " << (sizeof(Uint24_t) * 8) << " bits." << endl;
}
Uint24_t(uint32_t initVal) : data {0,0,0}
{
data[0] = static_cast<uint8_t>((initVal >> 0) & 0xff); // lsbyte
data[1] = static_cast<uint8_t>((initVal >> 8) & 0xff); //
data[2] = static_cast<uint8_t>((initVal >> 16) & 0xff); // msbyte
cout << "\n sizeof(Uint24_t)= " << sizeof(Uint24_t) // reports 3 bytes
<< " bytes, * 8= " << (sizeof(Uint24_t) * 8) << " bits." << endl;
}
~Uint24_t() = default;
std::string show() {
stringstream ss;
ss << " show(): "
<< static_cast<char>(data[2]) << "."
<< static_cast<char>(data[1]) << "."
<< static_cast<char>(data[0]);
return ss.str();
}
std::string dump() {
stringstream ss;
ss << " dump(): " << hex
<< static_cast<int>(data[2]) << "."
<< static_cast<int>(data[1]) << "."
<< static_cast<int>(data[0]);
return ss.str();
}
void swap0_2() { swap(data[0], data[2]); }
private:
uint8_t data[3]; // 3 uint8_t 's
};
class T976_t // ctor and dtor compiler provided defaults
{
public:
int operator()() { return exec(); } // functor entry
private: // methods
int exec()
{
Uint24_t u24(('c' << 16) + // msbyte
('b' << 8) +
('a' << 0));
cout << "\n sizeof(u24) = " << sizeof(u24) << " bytes"
<< "\n " << u24.show()
<< "\n " << u24.dump() << std::endl;
u24.swap0_2(); // swapping lsByte and msByte
cout << "\n sizeof(u24) = " << sizeof(u24) << " bytes"
<< "\n " << u24.show()
<< "\n " << u24.dump() << std::endl;
return 0;
}
}; // class T976_t
int main(int , char**) { return T976_t()(); } // call functor
Typical output:
sizeof(Uint24_t)= 3 bytes, * 8= 24 bits.
sizeof(u24) = 3 bytes
show(): c.b.a
dump(): 63.62.61
sizeof(u24) = 3 bytes
show(): a.b.c
dump(): 61.62.63

Can I use the ftw-function for class methods in C++?

I would like to use the ftw-function to recursivly traverse a filesystem structure. Additionally, the method shall be used inside of a class. Also, the entry-function, which is called by nftw(), belongs to the same class. That needs to be the case because the entry-function is supposed to change some class-members, dependent on the files that it finds.
When implementing such an approach, I get an error (see below). Is this an issue of syntax or is it not even possible to forward a pointer to a method to nftw()? In case it is not possible, do you know any alternative way to resursivly traverse a filesystem structure under linux?
class model
{
public:
boost::unordered_map<std::string, int> map;
int configure(const char *name)
{
// ...
ftw("DTModels/", this->ftw_entry, 15);
// ...
return = 0;
}
private:
int ftw_entry(const char *filepath, const struct stat *info, const int typeflag)
{
// Here I want to change the member 'map'
std::string filepath_s = filepath;
std::cout << "FTW_Entry: " << filepath_s << std::endl;
}
};
ERROR:
a pointer to a bound function may only be used to call the function
ftw("DTModels/", this->ftw_entry, 15);
I haven't used ftw in many many years and since you ask for an alternative, take a look at std::filesystem (C++17). Many pre-C++17 installations have it available via boost or experimental. If you use one of the pre-C++17 implementations, you many need to remove some of the stat lines from the below to make it work.
#include <iostream>
//#define I_HAVE_BOOST
#if __cplusplus >= 201703L
#include <filesystem>
namespace fs = std::filesystem;
#elif I_HAVE_BOOST
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
auto& out = std::cout;
void show_dent(const fs::directory_entry& dent) {
static size_t indent=0;
std::string ind(indent, ' ');
fs::file_status lstat = dent.symlink_status();
if( fs::is_symlink(lstat) ) {
fs::path pp = fs::read_symlink(dent);
out << ind << dent << " -> " << pp << "\n";
++indent;
show_dent(fs::directory_entry(pp));
--indent;
} else {
if(fs::is_directory(dent)) {
fs::directory_iterator dit_end;
std::cout << "Directory " << dent << " includes the following files:\n";
++indent;
for(auto dit = fs::directory_iterator(dent); dit != dit_end; ++dit) {
show_dent(*dit);
}
--indent;
} else {
fs::file_status stat = dent.status();
out << ind << dent << "\n"
<< ind << " stat\n"
<< ind << " is_regular_file : " << fs::is_regular_file(stat) << "\n"
<< ind << " is_directory : " << fs::is_directory(stat) << "\n"
<< ind << " is_block_file : " << fs::is_block_file(stat) << "\n"
<< ind << " is_character_file: " << fs::is_character_file(stat) << "\n"
<< ind << " is_fifo : " << fs::is_fifo(stat) << "\n"
<< ind << " is_socket : " << fs::is_socket(stat) << "\n"
<< ind << " is_symlink : " << fs::is_symlink(stat) << "\n"
<< ind << " exists : " << fs::exists(stat) << "\n";
if( fs::is_regular_file(stat) ) {
out
<< ind << " file_size : " << fs::file_size(dent) << "\n";
}
}
}
}
int main(int argc, char* argv[]) {
std::vector<std::string> args(argv+1, argv+argc);
out << std::boolalpha;
for(const auto& file_or_dir : args) {
show_dent(fs::directory_entry(file_or_dir));
}
return 0;
}

Making POD classes movable

I have a POD class and I want to make it movable for efficiency. I keep all the data in a std::array member object, and I make my public member variables references to parts of this std::array object. By doing this, now I am able to move the entire data by moving the std::array instance in the move constructor (I know that it is not literally a POD class anymore after writing constructors.).
Is this a good method of doing this? Does it actually move the data? See the code output below: After moving the std::array, I observe that both objects have the same values. It looks like it doesn't move, but it copies the data. What is the problem here?
#include <array>
class MyPodClass
{
private:
typedef double TYPE_x;
typedef double TYPE_y;
typedef double TYPE_z;
typedef int TYPE_p;
typedef int TYPE_r;
typedef int TYPE_s;
typedef char TYPE_k;
typedef char TYPE_l;
typedef char TYPE_m;
typedef float TYPE_a;
typedef float TYPE_b;
typedef float TYPE_c;
enum TypeSizes
{
STARTING_POSITION_x = 0,
STARTING_POSITION_y = STARTING_POSITION_x + sizeof(TYPE_x),
STARTING_POSITION_z = STARTING_POSITION_y + sizeof(TYPE_y),
STARTING_POSITION_p = STARTING_POSITION_z + sizeof(TYPE_z),
STARTING_POSITION_r = STARTING_POSITION_p + sizeof(TYPE_p),
STARTING_POSITION_s = STARTING_POSITION_r + sizeof(TYPE_r),
STARTING_POSITION_k = STARTING_POSITION_s + sizeof(TYPE_s),
STARTING_POSITION_l = STARTING_POSITION_k + sizeof(TYPE_k),
STARTING_POSITION_m = STARTING_POSITION_l + sizeof(TYPE_l),
STARTING_POSITION_a = STARTING_POSITION_m + sizeof(TYPE_m),
STARTING_POSITION_b = STARTING_POSITION_a + sizeof(TYPE_a),
STARTING_POSITION_c = STARTING_POSITION_b + sizeof(TYPE_b),
END_POSITION = STARTING_POSITION_c + sizeof(TYPE_c),
};
std::array<unsigned char, END_POSITION> MovableBulkData;
public:
MyPodClass()
: //x(*static_cast<TYPE_x*>(&MovableBulkData[STARTING_POSITION_x])), // ERROR: Invalid type conversion. Why?
x(*(TYPE_x*)(&MovableBulkData[STARTING_POSITION_x])),
y(*(TYPE_y*)(&MovableBulkData[STARTING_POSITION_y])),
z(*(TYPE_z*)(&MovableBulkData[STARTING_POSITION_z])),
p(*(TYPE_p*)(&MovableBulkData[STARTING_POSITION_p])),
r(*(TYPE_r*)(&MovableBulkData[STARTING_POSITION_r])),
s(*(TYPE_s*)(&MovableBulkData[STARTING_POSITION_s])),
k(*(TYPE_k*)(&MovableBulkData[STARTING_POSITION_k])),
l(*(TYPE_l*)(&MovableBulkData[STARTING_POSITION_l])),
m(*(TYPE_m*)(&MovableBulkData[STARTING_POSITION_m])),
a(*(TYPE_a*)(&MovableBulkData[STARTING_POSITION_a])),
b(*(TYPE_b*)(&MovableBulkData[STARTING_POSITION_b])),
c(*(TYPE_c*)(&MovableBulkData[STARTING_POSITION_c]))
{
}
MyPodClass(MyPodClass && RValue)
: MovableBulkData(std::move(RValue.MovableBulkData)),
x(*(TYPE_x*)(&MovableBulkData[STARTING_POSITION_x])),
y(*(TYPE_y*)(&MovableBulkData[STARTING_POSITION_y])),
z(*(TYPE_z*)(&MovableBulkData[STARTING_POSITION_z])),
p(*(TYPE_p*)(&MovableBulkData[STARTING_POSITION_p])),
r(*(TYPE_r*)(&MovableBulkData[STARTING_POSITION_r])),
s(*(TYPE_s*)(&MovableBulkData[STARTING_POSITION_s])),
k(*(TYPE_k*)(&MovableBulkData[STARTING_POSITION_k])),
l(*(TYPE_l*)(&MovableBulkData[STARTING_POSITION_l])),
m(*(TYPE_m*)(&MovableBulkData[STARTING_POSITION_m])),
a(*(TYPE_a*)(&MovableBulkData[STARTING_POSITION_a])),
b(*(TYPE_b*)(&MovableBulkData[STARTING_POSITION_b])),
c(*(TYPE_c*)(&MovableBulkData[STARTING_POSITION_c]))
{
}
const MyPodClass & operator=(MyPodClass && RValue)
{
MovableBulkData = std::move(RValue.MovableBulkData);
return *this;
}
TYPE_x & x;
TYPE_y & y;
TYPE_z & z;
TYPE_p & p;
TYPE_r & r;
TYPE_s & s;
TYPE_k & k;
TYPE_l & l;
TYPE_m & m;
TYPE_a & a;
TYPE_b & b;
TYPE_c & c;
};
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
MyPodClass PodObject1, PodObject2;
PodObject1.y = 3.4;
PodObject1.s = 4;
PodObject1.m = 'm';
PodObject1.a = 2.3f;
std::cout << "PodObject1.y = " << PodObject1.y << std::endl;
std::cout << "PodObject1.s = " << PodObject1.s << std::endl;
std::cout << "PodObject1.m = " << PodObject1.m << std::endl;
std::cout << "PodObject1.a = " << PodObject1.a << std::endl << std::endl;
std::cout << "PodObject2.y = " << PodObject2.y << std::endl;
std::cout << "PodObject2.s = " << PodObject2.s << std::endl;
std::cout << "PodObject2.m = " << PodObject2.m << std::endl;
std::cout << "PodObject2.a = " << PodObject2.a << std::endl << std::endl;
std::cout << "Moving PodObject1 to PodObject2..." << std::endl << std::endl;
PodObject2 = std::move(PodObject1);
std::cout << "PodObject1.y = " << PodObject1.y << std::endl;
std::cout << "PodObject1.s = " << PodObject1.s << std::endl;
std::cout << "PodObject1.m = " << PodObject1.m << std::endl;
std::cout << "PodObject1.a = " << PodObject1.a << std::endl << std::endl;
std::cout << "PodObject2.y = " << PodObject2.y << std::endl;
std::cout << "PodObject2.s = " << PodObject2.s << std::endl;
std::cout << "PodObject2.m = " << PodObject2.m << std::endl;
std::cout << "PodObject2.a = " << PodObject2.a << std::endl << std::endl;
std::cout << "Modifying PodObject1 and PodObject2..." << std::endl << std::endl;
PodObject1.s = 5;
PodObject2.m = 'n';
std::cout << "PodObject1.y = " << PodObject1.y << std::endl;
std::cout << "PodObject1.s = " << PodObject1.s << std::endl;
std::cout << "PodObject1.m = " << PodObject1.m << std::endl;
std::cout << "PodObject1.a = " << PodObject1.a << std::endl << std::endl;
std::cout << "PodObject2.y = " << PodObject2.y << std::endl;
std::cout << "PodObject2.s = " << PodObject2.s << std::endl;
std::cout << "PodObject2.m = " << PodObject2.m << std::endl;
std::cout << "PodObject2.a = " << PodObject2.a << std::endl << std::endl;
std::cout << std::endl;
_wsystem(L"timeout /t 60 /nobreak");
return 0;
}
Output:
PodObject1.y = 3.4
PodObject1.s = 4
PodObject1.m = m
PodObject1.a = 2.3
PodObject2.y = -9.25596e+61
PodObject2.s = -858993460
PodObject2.m = ╠
PodObject2.a = -1.07374e+08
Moving PodObject1 to PodObject2...
PodObject1.y = 3.4
PodObject1.s = 4
PodObject1.m = m
PodObject1.a = 2.3
PodObject2.y = 3.4
PodObject2.s = 4
PodObject2.m = m
PodObject2.a = 2.3
Modifying PodObject1 and PodObject2...
PodObject1.y = 3.4
PodObject1.s = 5
PodObject1.m = m
PodObject1.a = 2.3
PodObject2.y = 3.4
PodObject2.s = 4
PodObject2.m = n
PodObject2.a = 2.3
This is a misuse of move semantics. Since your class contains a number of simple data members like int and float, there is really nothing to move. You'd be better off with memcpy(), which is probably close to what your compiler gives you for free if you just write the class the normal, naive way, with no std::array and no pointer gymnastics.
Move semantics would have been useful here if your class contained e.g. a std::string, because std::string uses dynamically allocated memory which can be "moved" (read: adopted) into the target of a move.
The above of course means that you could "fix" your problem by dynamically allocating the array, which would allow you to move it. But in the end this would be a baroque way to achieve the effect of using a trivial POD class with no gymnastics and storing it in a std::unique_ptr, which of course enables move semantics.

How to format text using std:out setfill std::setw std:right with one padding space

I just want to format a string and an integer value with right justify.
There is no problem to do this without leading space before the integer value.
bytes.....................123981
total bytes..............1030131
But it should look like this:
bytes ................... 123981
total bytes ............ 1030131
Unfortunately the example below wont work, because setw (right justify) relates only to the next stream element.
int iBytes = 123981;
int iTotalBytes = 1030131;
cout << setfill('.');
cout << right;
cout << "bytes " << setw(20) << " " << iBytes << endl;
cout << "total bytes " << setw(14) << " " << iTotalBytes << endl;
I hardly ever use std::cout, so is there a simple way to do this without previously joining a space char to the value?
The simplest way would be to write your " " and value into a std::stringstream and write the resulting str() into your output stream like:
std::stringstream ss;
ss << " " << iBytes;
cout << "bytes " << setw(20) << ss.str() << endl;
And here comes the complete overkill. A templated class prefixed which can be printed and bundles the two constructor arguments prefix,val into one string to be printed. number format, and precision is taken from the final output stream. Works with ints,floats, strings and const char *. And should work with every arg that has a valid output operator.
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
template<class T>
class prefixed_base {
public:
prefixed_base(const std::string & prefix,const T val) : _p(prefix),_t(val) {
}
protected:
std::string _p;
T _t;
};
// Specialization for const char *
template<>
class prefixed_base<const char*> {
public:
prefixed_base(const std::string & prefix,const char * val) : _p(prefix),_t(val) {
}
protected:
std::string _p;
std::string _t;
};
template<class T>
class prefixed : public prefixed_base<T> {
private:
typedef prefixed_base<T> super;
public:
prefixed(const std::string & prefix,const T val) : super(prefix,val) {
}
// Output the prefixed value to an ostream
// Write into a stringstream and copy most of the
// formats from os.
std::ostream & operator()(std::ostream & os) const {
std::stringstream ss;
// We 'inherit' all formats from the
// target stream except with. This Way we
// keep informations like hex,dec,fixed,precision
ss.copyfmt(os);
ss << std::setw(0);
ss << super::_p;
ss.copyfmt(os);
ss << std::setw(0);
ss << super::_t;
return os << ss.str();
}
};
// Output operator for class prefixed
template<class T>
std::ostream & operator<<(std::ostream & os,const prefixed<T> & p) {
return p(os);
}
// This function can be used directly for output like os << with_prefix(" ",33.3)
template<class T>
prefixed<T> with_prefix(const std::string & p,const T v) {
return prefixed<T>(p,v);
}
int main() {
int iBytes = 123981;
int iTotalBytes = 1030131;
cout << setfill('.');
cout << right;
cout << "bytes " << setw(20) << with_prefix(" ",iBytes) << endl;
cout << "total bytes " << setw(14) << with_prefix(" ",iTotalBytes) << endl;
cout << "bla#1 " << setw(20) << std::fixed << std::setprecision(9) << with_prefix(" ",220.55) << endl;
cout << "blablabla#2 " << setw(14) << std::hex << with_prefix(" ",iTotalBytes) << endl;
}
#Oncaphillis thx for the piece of source code, I adapt it a bit for my needs. I just wrote a function to convert values. std::to_string is used by C++11 standard, so I decided to use _to_string/_to_wstring instead. The tricky part was to get "wcout" to work with UNICODEs on Windows console. I didn’t really manage it, so I had to do a workaround. Anyway to print e.g. Cyrillic characters you have to change the console font to Consolas or Lucida.
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
#if defined(UNICODE) || defined(_UNICODE)
#define _tcout std::wcout
#define _to_tstring _to_wstring
template <typename T>std::wstring _to_wstring(const T& value) {
std::wostringstream wos;
wos.copyfmt(std::wcout);
wos << value;
return wos.str();
}
#else
#define _tcout std::cout
#define _to_tstring _to_string
template <typename T> std::string _to_string(const T& value) {
std::ostringstream os;
os.copyfmt(std::cout);
os << value;
return os.str();
}
#endif
int _tmain(int argc, _TCHAR* argv[]) {
int iBytes = 123981;
int iTotalBytes = 1030131;
#if defined(UNICODE) || defined(_UNICODE)
wostringstream newCoutBuffer;
wstreambuf* oldCoutBuffer = _tcout.rdbuf(newCoutBuffer.rdbuf()); // redirect cout buffer
#endif
_tcout.imbue(std::locale("German")); // enable thousand separator
_tcout.precision(0);
_tcout << setfill(_T('.')) << right << fixed;
_tcout << _T("bytes ") << setw(20) << _T(" ") + _to_tstring(iBytes) << endl;
_tcout << _T("bytes total ") << setw(14) << _T(" ") + _to_tstring(iTotalBytes) << endl;
_tcout << _T("bla bla ") << fixed << setprecision(9); _tcout << setw(18) << _T(" ") + _to_tstring(0.1337) << endl;
_tcout << _T("Милые женщины ") << hex; _tcout << setw(12) << _T(" ") + _to_tstring(iTotalBytes) << endl;
_tcout << _T("retries ") << dec; _tcout << setw(18) << _T(" ") + _to_tstring(2) + _T(" of ") + _to_tstring(20) << endl;
#if defined(UNICODE) || defined(_UNICODE)
DWORD dwWritten;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), newCoutBuffer.str().c_str(),newCoutBuffer.tellp(),&dwWritten,NULL);
_tcout.rdbuf(oldCoutBuffer);
#endif
return 0;
}
Output:
bytes ............ 123.981
bytes total .... 1.030.131
bla bla ...... 0,133700000
Милые женщины ..... fb.7f3
retries .......... 2 of 20

Optimizing initialization on maps: forwarding the key

I've got a question that should be interesting. I'd like to "forward initialize" an item in a std::unordered_map upon construction.
These are the details. I've got a hash map from std::string to a custom class prop, which in my dreams, would initialize a member variable calculating the hash of the string passed to std::unordered_map::operator[].
This is a handy code I've written, but I don't know where to start.
Why this trouble? Because I'd like to avoid something like "if the string is NOT in the container calculate the hash; do stuff with prop". Avoiding this if could be something that might affect my performances. So the constructor, as well as the hashing, will be executed only once, when the map adds a new item in the container. It would be great.
Any hints?
Thanks & Cheers!
#include <iostream>
#include <string>
#include <unordered_map>
class prop
{
public:
prop(std::string s = "") : s_(s), hash_(std::hash<std::string>()(s))
{
// Automagically forwarding the string in the unordered_map...
};
std::string s_;
std::size_t hash_;
int x;
};
int main(int argc, const char * argv[])
{
// Forward the std::string to the prop constructor... but how?
std::unordered_map<std::string, prop> map;
map["ABC"].x = 1;
map["DEF"].x = 2;
map["GHI"].x = 3;
map["GHI"].x = 9; // This should not call the constructor: the hash is there already
std::cout << map["ABC"].x << " : " << map["ABC"].s_ << " : " << map["ABC"].hash_ << std::endl;
std::cout << map["DEF"].x << " : " << map["DEF"].s_ << " : " << map["DEF"].hash_ << std::endl;
std::cout << map["GHI"].x << " : " << map["GHI"].s_ << " : " << map["GHI"].hash_ << std::endl;
std::cout << map["XXX"].x << " : " << map["XXX"].s_ << " : " << map["XXX"].hash_ << std::endl;
return 0;
}
Just use your prop class as a key, instead of string:
#include <iostream>
#include <string>
#include <unordered_map>
class prop
{
public:
prop(std::string s = "") : s_(s), hash_(std::hash<std::string>()(s))
{
// Automagically forwarding the string in the unordered_map...
};
std::string s_;
std::size_t hash_;
};
int main(int argc, const char * argv[])
{
// Forward the std::string to the prop constructor... but how?
std::unordered_map<prop, int, ...> map( ... );
prop pABC( "ABC" ), pDEF( "DEF" ), pGHI( "GHI" );
map[pABC] = 1;
map[pDEF] = 2;
map[pGHI] = 3;
map[pGHI] = 9;
std::cout << map[pABC] << " : " << pABC.s_ << " : " << pABC.hash_ << std::endl;
std::cout << map[pDEF] << " : " << pDEF.s_ << " : " << pDEF.hash_ << std::endl;
std::cout << map[pGHI] << " : " << pGHI.s_ << " : " << pGHI.hash_ << std::endl;
prop pXXX( "XXX" );
std::cout << map[pXXX] << " : " << pXXX.s_ << " : " << pXXX.hash_ << std::endl;
return 0;
}
I omitted custom hash and compare function, the idea should be clear without it.