Problem with std::make_tuple in C++0x - c++

Tying to compile the following program with Visual Studio 10, I get lot of compile errors:
#include "stdafx.h"
#include <tuple>
#include <string>
#include <map>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
typedef std::tuple<std::string, std::string> key_t;
typedef std::map<key_t, std::string> map_t;
map_t the_map;
auto k = std::make_tuple("one", "two");
the_map[k] = "the value";
auto q = std::make_tuple("one", "two");
auto i = the_map.find(q);
std::cout << i->second << std::endl;
return 0;
}
Error 1 error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'const key_t' to 'const std::basic_string<_Elem,_Traits,_Ax> &' c:\program files (x86)\microsoft visual studio 10.0\vc\include\tuple 127 1 tuple
Coming from the line:
std::cout << i->second << std::endl;
Strange thing is, as least from my point of view, if I change these lines:
auto k = std::make_tuple("one", "two");
the_map[k] = "the value";
to
the_map[std::make_tuple("one", "two")] = "p";
the program compiles. So my question is of course why? I guess it has something to do with make_tuple and move semantics - but I do not understand what..

Apparently the error comes in fact from the line the_map[k] = "the value";
When you use the [] operator on a map, the library tries to create a std::pair<Key,Value> object. In your case, this becomes std::pair<std::tuple<std::string,std::string>,std::string>.
However if you use an intermediate variable k, the constructor of std::pair which is called is: (copy-pasted from the standard lib)
_Pair_base(const _Ty1x& _Val1, _Ty2x&& _Val2)
: first(_Val1), second(_STD move(_Val2))
{ // construct from specified values
}
This constructor is trying to make a copy of your key_t. Unfortunatly, the tuple implementation of MSVC++ is bugged at the moment and the copy fails to compile (see also this: C++0x : are tuples of tuples allowed?)
I can diagnosize more, because this implementation is not only bugged but also very complicated.
Boost's tuples should work but don't have an < operator, so you can't use them.
The "best" solution for the moment is to write the_map.insert(std::make_pair(k, "the value"));

This looks like a bug in VS10, for some reason it's trying to cast the key type to the value type.
This simplified version also fails.
typedef std::map<std::tuple<int, int>, int> map_t;
map_t the_map;
map_t::key_type k = std::make_tuple(1,2);
the_map[k] = 3;
Produces the following:
error C2440: 'initializing' : cannot convert from 'const std::tr1::tuple<_Arg0,_Arg1>' to 'int'

Related

(Learning C++) Why is my compiler reporting errors when I try to make a tuple?

I'm new to c++ and have taken the liberty to learn it this summer after coming from a python background. I was watching a video about how to create and use tuples within c++ and it seemed to have worked for the YouTuber, however when I replicated his steps, my compiler had thrown some errors even though there was no distinct differences in the code
code:
#include <iostream>
#include <string>
#include <tuple>
int main() {
std::tuple <int, std::string> person(18, "Chris");
std::cout << std::get<1>(person) << std::endl;
return 0;
}
Errors:
❯ g++ -o main Tuples.cpp && ./main
Tuples.cpp:7:10: error: no member named 'tuple' in namespace 'std'
std::tuple <int, std::string> person(18, "Chris");
~~~~~^
Tuples.cpp:7:20: error: expected '(' for function-style cast or type construction
std::tuple <int, std::string> person(18, "Chris");
~~~^
Tuples.cpp:8:30: error: use of undeclared identifier 'person'
std::cout << std::get<1>(person) << std::endl;
^
3 errors generated.
Video for reference: https://www.youtube.com/watch?v=T9-agjKW4PQ&list=PLzMcBGfZo4-lmGC8VW0iu6qfMHjy7gLQ3&index=16

Construct pair of unique_ptr<int> and int

I'm trying to create a pair of int and a unique_ptr. How should I use make_pair to create this ?
#include <string>
#include <memory>
#include <algorithm>
int main()
{
std::unique_ptr<int> p = std::make_unique<int>(0);
std::pair<int, std::unique_ptr<int>> pr = std::make_pair((int)0, p);
}
I run into the following issue,
Error C2440 '<function-style-cast>': cannot convert from 'initializer list' to '_Mypair' templpairuniqueptr c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\utility 405
I could not understand why this happens. I'm on MSVC.
You cannot copy unique pointers. After all, the copy would not be unique. Move instead:
auto pr = std::make_pair(
0, std::make_unique<int>(0)
);
You can move from lvalues as well, if you need to, by converting the lvalue to an rvalue with std::move:
auto pr = std::make_pair(
0, std::move(p)
);

Assigning to ostream_iterators using *

On page 107 of Stroustrup's The C++ Programming language (4th ed) is an example of writing to ostream_iterators through assignment to them. A word for word copy of a subset of the example is below, but I can not compile it on VS2015 without an error and I do not understand the error message
std::ostream_iterator<string> oo { cout };
*oo2 = "Hello, "; // compile error, see below
++oo2;
I also tried
*oo2 = string("Hello"); // same error
the beginning of the very long error message follows
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\iterator(317): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const std::string' (or there is no acceptable conversion)
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(495): note: could be 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_streambuf<char,std::char_traits<char>> *)'
<...more...>
A different version using char *'s works fine:
// works
std::ostream_iterator<const char *> oo5{ std::cout }; //const or no const, either works
*oo5 = "hello, ";
++oo5;
*oo5 = " world\n";
What is wrong with the string version? Is this a error in the book or on my part somehow? Thanks
edit
I'll also note that:
std::ostream_iterator<char> oo{ std::cout };
string s{ "hello, stream_iterator<char>, copy string" };
std::copy(s.begin(), s.end(), oo);
works
Your code has a typo. Does this work any better?
#include <iostream>
#include <ostream>
#include <string>
int main()
{
std::ostream_iterator<std::string> oo2{ std::cout };
*oo2 = "Hello, ";
++oo2;
return 0;
}
I get this output:
Hello,

Using auto in loop error "auto must have an initializer"

I want to use the auto keyword but get this error when compiling (Visual C++ Express 2010)
typedef std::list<int> MyList;
int main()
{
const int args[] = {0, 1, 2};
MyList myList(std::begin(args), std::end(args));
for(auto& value : myList)
{
std::cout << value << std::endl;
}
}
Output:
error C2143: syntax error : missing ',' before ':'
error C2530: 'value' : references must be initialized
error C3531: 'value': a symbol whose type contains 'auto' must have an initializer
The C++ compiler in VS2010 does support range-based for loops, but with a pre-standard syntax.
(And seriously, you can't expect a compiler finished about 2 years before the Standard to be fully compliant)
for each (int& value in myList)
{
std::cout << value << std::endl;
}
There are two issues in your code:
You need to explicitly include the headers for the functionality you use.
#include <list>
#include <iostream>
VS2010 does not support C++11 range-based "for" loops. The feature was implemented much later. See the following table: http://msdn.microsoft.com/en-us/library/hh567368.aspx

C++ type cast operator code that won't compile in visual studio 2012, but worked fine in visual studio 2005

I'm trying to update a old project that has been building with visual studio 2005 to uses visual studio 2012, and I'm getting an error that I cant solve.
The code that works fine under VS2005:
#include <iostream>
#include <string>
#include <sstream>
using std::cout;
using std::wcout;
using std::endl;
using std::wstring;
using std::string;
class Value
{
public:
Value(const wstring& value)
{
v = value;
}
Value(Value& other)
{
this->v = other.v;
}
template<typename T>
operator T() const
{
T reply;
std::wistringstream is;
is.str(v);
is >> reply;
return reply;
}
operator wstring() const
{
return v;
}
private:
wstring v;
};
int main()
{
Value v(L"Hello World");
wstring str = v;
wcout << str << endl;
Value int_val(L"1");
int i = int_val;
cout << i + 1 << endl;
return 0;
}
When I'm compiling this under VS2012 I get an error on the line "wstring str = v;", the error is:
error C2440: 'initializing' : cannot convert from 'Value' to 'std::basic_string<_Elem,_Traits,_Alloc>'
1> with
1> [
1> _Elem=wchar_t,
1> _Traits=std::char_traits<wchar_t>,
1> _Alloc=std::allocator<wchar_t>
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
I can kinda fix it by changing the operator signature from 'operator wstring() const' to 'operator const wstring&() const'. But why does the original code not work, even though it works in VS2005.
I'm not getting an error on the line "int i = int_val;".
This also compiles and runs fine with GCC (g++) in cygwin (version 4.5.3).
Update
To really simulate my real problem there was some information left out in the sample code above. In between the Value class and the usage is a few other classes. One that look like this:
class Config
{
public:
virtual Value getValue(const string& key) const = 0;
Value operator()(const string& key)
{
return getValue(key);
}
};
And the usage
const wstring value2 = config("key");
That will give the error above when compiling but also IntelliSense will give other hints on whats wrong and it says: "More than one user-defined conversion from "Value" to "const std::wstring" applies:" and it points at both the regular constructor and the move constructor of basic_string. So it seem to have something to do with rvalues to do and I have been reading up on that, and understand the basics. But there is probably a lot I am missing.
I find that I can fix this problem by changing the usage to:
const wstring&& value = config("key");
Then it seem like the VS2012 compiler understand which constructor it should use then.
Questions:
* Are there a way to not use && in this example?
* What is really happening here?
I put up the sample code on GitHub:
https://github.com/Discordia/ImplicitTypeConversion
In simple (hopefully not simplified) terms, with C++11, you'll have to start thinking of references in terms of lvalue and rvalue. Basically, C++11 gives you the ability to handle operations on references differently depending on whether or not you are dealing with a "temporary" object. This gives you ability to do things like move data internal to your object rather than copy in different situations. The down side to this is the effect you are seeing, where old code is not specific enough about which you are dealing with. There's more to it than that, it's not really something that can be fully explained in a short SO answer, but previous answers gave some good places to start. I would rework your code to provide both rvalue and lvalue operators (which it sounds like you're already on your way to doing).