STL operator= behavior change with Visual Studio 2010? - c++

I am attempting to compile QtScriptGenerator (gitorious) with Visual Studio 2010 (C++) and have run into a compile error. In searching for a solution, I have seen occasional references to compile breakages introduced since VS2008 due to changes in VS2010's implementation of STL and/or c++0x conformance changes.
Any ideas what is happening below, or how I could go about fixing it? If the offending code appeared to be QtScriptGenerator's, I think I would have an easier time fixing it.. but it appears to me that the offending code may be in VS2010's STL implementation and I may be required to create a workaround?
PS. I am pretty unfamiliar with templates and STL. I have a background in embedded and console projects where such things have until recently often been avoided to reduce memory consumption and cross-compiler risks.
Edit - It appears it is probably Visual Studio's implementation of std::copy which changed.
C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xutility(275) : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'rpp::pp_output_iterator<_Container>' (or there is no acceptable conversion)
with
[
_Container=std::string
]
c:\qt\qtscriptgenerator\generator\parser\rpp\pp-iterator.h(75): could be 'rpp::pp_output_iterator<_Container> &rpp::pp_output_iterator<_Container>::operator =(const char &)'
with
[
_Container=std::string
]
while trying to match the argument list '(rpp::pp_output_iterator<_Container>, rpp::pp_output_iterator<_Container>)'
with
[
_Container=std::string
]
C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xutility(2176) : see reference to function template instantiation '_Iter &std::_Rechecked<_OutIt,_OutIt>(_Iter &,_UIter)' being compiled
with
[
_Iter=rpp::pp_output_iterator<std::string>,
_OutIt=rpp::pp_output_iterator<std::string>,
_UIter=rpp::pp_output_iterator<std::string>
]
c:\qt\qtscriptgenerator\generator\parser\rpp\pp-internal.h(83) : see reference to function template instantiation '_OutIt std::copy<std::_String_iterator<_Elem,_Traits,_Alloc>,_OutputIterator>(_InIt,_InIt,_OutIt)' being compiled
with
[
_OutIt=rpp::pp_output_iterator<std::string>,
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>,
_OutputIterator=rpp::pp_output_iterator<std::string>,
_InIt=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>
]
c:\qt\qtscriptgenerator\generator\parser\rpp\pp-engine-bits.h(500) : see reference to function template instantiation 'void rpp::_PP_internal::output_line<_OutputIterator>(const std::string &,int,_OutputIterator)' being compiled
with
[
_OutputIterator=rpp::pp_output_iterator<std::string>
]
C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xutility(275) : error C2582: 'operator =' function is unavailable in 'rpp::pp_output_iterator<_Container>'
with
[
_Container=std::string
]
Here's some context..
pp-internal.h
#ifndef PP_INTERNAL_H
#define PP_INTERNAL_H
#include <algorithm>
#include <stdio.h>
namespace rpp {
namespace _PP_internal
{
..
64 template <typename _OutputIterator>
65 void output_line(const std::string &__filename, int __line, _OutputIterator __result)
66 {
67 std::string __msg;
68
69 __msg += "# ";
70
71 char __line_descr[16];
72 pp_snprintf (__line_descr, 16, "%d", __line);
73 __msg += __line_descr;
74
75 __msg += " \"";
76
77 if (__filename.empty ())
78 __msg += "<internal>";
79 else
80 __msg += __filename;
81
82 __msg += "\"\n";
83 std::copy (__msg.begin (), __msg.end (), __result);
84 }
pp-engine-bits.h
#ifndef PP_ENGINE_BITS_H
#define PP_ENGINE_BITS_H
#include <stdio.h>
namespace rpp {
450 template <typename _InputIterator, typename _OutputIterator>
451 void pp::operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result)
452 {
..
497 if (env.current_line != was)
498 {
499 env.current_line = was;
500 _PP_internal::output_line (env.current_file, env.current_line, __result);
501 }
.. and here's the definition of pp_output_iterator
pp-iterator.h
#ifndef PP_ITERATOR_H
#define PP_ITERATOR_H
#include <iterator>
namespace rpp {
..
template <typename _Container>
class pp_output_iterator
: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
std::string &_M_result;
public:
explicit pp_output_iterator(std::string &__result):
_M_result (__result) {}
inline pp_output_iterator &operator=(typename _Container::const_reference __v)
{
if (_M_result.capacity () == _M_result.size ())
_M_result.reserve (_M_result.capacity () << 2);
_M_result.push_back(__v);
return *this;
}
inline pp_output_iterator &operator * () { return *this; }
inline pp_output_iterator &operator ++ () { return *this; }
inline pp_output_iterator operator ++ (int) { return *this; }
};

I think that the problem is that std::copy is trying to use 'copy assignment' (operator=()) on your rpp::pp_output_iterator<> and there is no operator=() for that class template. I should say, there is an operator=() but it doesn't take the correct parameter to be the 'copy assignment' function (ie., it doesn't take a ``rpp::pp_output_iterator<>&parameter). I think that the existence of someoperator=()` function will prevent the compiler from generating a default (I don't have access to the standard document at the moment to verify this 100%).
Note that a type must be assignable (among other things, of course) to be considered an OutputIterator: http://www.sgi.com/tech/stl/OutputIterator.html
Previous versions of std::copy in MSVC might not have actually used assignment (just because OutputIterator must support it doesn't mean std::copy has to use it), which is why it might be a 'new' error in VS2010. (I can't check right now due to limited access to my tools).

I added these code to pp-iterator.h for template class pp_output_iterator, and can fix this issue:
inline pp_output_iterator &operator=(const typename pp_output_iterator<_Container>& __v)
{
_M_result = __v._M_result;
return *this;
}

I had this same problem. The things guesser is saying here did not make much sense to me against the code I got from the git repo (head on 4.7.2011), so I went around this in another way.
This problem is only in the generator project that make a generator that produces the generated code that is utilized by the qtbindings project. The simple fact is that you don't have to use VC10 to build the generator, you can use Qt provided VC9 build to make the generator this will not produce the OP mentioned build errors.
Before running the generator: Remember to change QTDIR to the VC10 Qt build you want the bindings against, or I guess that doesn't matter anyways if the version number is the same. The generator.exe will be built in the release folder, copy that and QtCore and QtXml dll:s to the parent folder from your VC9 Qt that you built the generator against.
After this build the qtbindings project with VC10. I had some minor problems there like it had linker output extensions as .lib, just change all of those to .dll and it should go trough.
Hope this helps people if they have probs with this in the future as Visual Studio 10 gets more traction :) Hopefully the maintainers will fix the build error at some point.

Related

Using lambda expression as Compare for std::set, when it's inside a vector

I want to use a lambda expression as custom Compare for a std::set of integers. There are many answers on this site explaining how to do this, for example https://stackoverflow.com/a/46128321/10774939. And indeed,
#include <vector>
#include <set>
#include <iostream>
int main() {
auto different_cmp = [](int i, int j) -> bool {
return j < i;
};
std::set<int, decltype(different_cmp)> integers(different_cmp);
integers.insert(3);
integers.insert(4);
integers.insert(1);
for (int integer : integers) {
std::cout << integer << " ";
}
return 0;
}
compiles and outputs
4 3 1
as expected. However, when I try to put this set in a vector with
std::vector<std::set<int, decltype(different_cmp)>> vec_of_integers;
vec_of_integers.push_back(integers);
the compiler complains. I'm using Visual Studio 2017 and I get different compiler errors depending on the surrounding code. In the above example, it's
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\utility(77): error C2664: 'void std::swap(std::exception_ptr &,std::exception_ptr &) noexcept': cannot convert argument 1 from '_Ty' to 'std::exception_ptr &'
1> with
1> [
1> _Ty=main::<lambda_48847b4f831139ed92f5310c6e06eea1>
1> ]
Most of the errors I've seen so far with this seem to have to do with copying the set.
So my question is:
Why does the above code not work and how can I make it work, while still using a locally defined lambda?
This seems to be a bug in MS compiler as it compiles well with GCC and Clang.
To make it work in MS Compiler (Visual Studio 2017) you can do this:
std::vector<std::set<int, decltype(different_cmp)>> vec_of_integers{integers};
This compiles cleanly. See here.

how to deal with a c++ related warning in boost option header file?

i have Microsoft Visual Studio (MSVS) 2012 Pro and i have set warning level to a slightly elevated level of 4. when doing this i am getting warnings for some of the included header files from the boost library. the message is this:
C:\Users\****\boost/optional/optional.hpp(595): warning C4244: 'initializing' : conversion from 'T_DOUBLE' to 'float', possible loss of data
C:\Users\****\boost/optional/optional.hpp(430) : see reference to function template instantiation 'void boost::optional_detail::optional_base<T>::construct<double>(Expr &&,const void *)' being compiled
with
[
T=T_FLOAT,
Expr=T_DOUBLE
]
C:\Users\****\boost/optional/optional.hpp(430) : see reference to function template instantiation 'void boost::optional_detail::optional_base<T>::construct<double>(Expr &&,const void *)' being compiled
with
[
T=T_FLOAT,
Expr=T_DOUBLE
]
the code in the file leading to this warning is this (line 610 on most recent beta of boost 1.64.0.B2 still resembles it exactly - but i am not on the beta now):
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Constructs using any expression implicitly convertible to the single argument
// of a one-argument T constructor.
// Converting constructions of optional<T> from optional<U> uses this function with
// 'Expr' being of type 'U' and relying on a converting constructor of T from U.
template<class Expr>
void construct ( Expr&& expr, void const* )
{
new (m_storage.address()) value_type(boost::forward<Expr>(expr)) ;
m_initialized = true ;
}
what is the reason (=learn to understand) for this warning and how to eliminate it in the boost header for me any anyone else? alternatively thinking: does it make sense to "fix" it in such a global way, or is there a deeper meaning pointing rather to somewhere else (either boost or application codes) to improve or fix those other codes?
You are probably passing a double literal into method that expects float. Something like foo(1.0) instead of foo(1.0f)

Visual studio using the wrong template function for chrono::duration division

I was converting over some code to use the c++11 chrono library rather than using the ctime library, at least in part to get a better understanding on the chrono library. Most of it has gone great, except for trying to do division by two chrono::durations. I've reduced the offending code down to a simple example and it took me a while to figure out why it was giving me the error it is.
#include <chrono>
using namespace std;
int main()
{
chrono::milliseconds tickLength(16);
chrono::milliseconds futureDuration(200);
auto numTicks = futureDuration / tickLength;
}
This should access the function
template<class _Rep1,
class _Period1,
class _Rep2,
class _Period2> inline
typename common_type<_Rep1, _Rep2>::type
operator/(
const duration<_Rep1, _Period1>& _Left,
const duration<_Rep2, _Period2>& _Right)
but instead appears to be trying to use
template<class _Rep1,
class _Period1,
class _Rep2> inline
typename enable_if<is_convertible<_Rep2,
typename common_type<_Rep1, _Rep2>::type>::value
&& !_Is_duration<_Rep2>::value,
duration<typename common_type<_Rep1, _Rep2>::type, _Period1> >::type
operator/(
const duration<_Rep1, _Period1>& _Left,
const _Rep2& _Right)
and thus is trying to determine a common type between milliseconds and long long. The compiler output is:
1>------ Build started: Project: Playground, Configuration: Debug Win32 ------
1> playground.cpp
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\type_traits(1446): error C2446: ':' : no conversion from 'std::chrono::milliseconds' to '__int64'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> c:\users\XXX\documents\visual studio 2013\projects\playground\playground\playground.cpp(9) : see reference to class template instantiation 'std::common_type<__int64,std::chrono::milliseconds>' being compiled
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Am I doing something wrong in my code?
Is this a visual studio issue?
Is this a c++11 standard issue?
Your example code compiles for me using clang/libc++. And your description of what should be happening sounds right to me. Further, if I print out numTicks, I get 12, which is 200/16 (integer division).
Sounds like a visual stdio bug to me. I see nothing wrong with your code.

Filling std::map with std::transform (error: cannot deduce argument)

I'm trying to fill std::map with std::transform. Next code compiles without error:
std::set<std::wstring> in; // "in" is filled with data
std::map<std::wstring, unsigned> out;
std::transform(in.begin(), in.end()
, boost::counting_iterator<unsigned>(0)
, std::inserter(out, out.end())
, [] (std::wstring _str, unsigned _val) { return std::make_pair(_str, _val); }
);
But If I replace string
, [] (std::wstring _str, unsigned _val) { return std::make_pair(_str, _val); }
with
, std::make_pair<std::wstring, unsigned>
or
, std::ptr_fun(std::make_pair<std::wstring, unsigned>)
I get errors:
foo.cpp(327): error C2784: '_OutTy *std::transform(_InIt1,_InIt1,_InTy (&)[_InSize],_OutTy (&)[_OutSize],_Fn2)' : could not deduce template argument for '_InTy (&)[_InSize]' from 'boost::counting_iterator<Incrementable>'
with
[
Incrementable=unsigned int
]
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm(1293) : see declaration of 'std::transform'
foo.cpp(327): error C2784: '_OutTy *std::transform(_InIt1,_InIt1,_InIt2,_OutTy (&)[_OutSize],_Fn2)' : could not deduce template argument for '_OutTy (&)[_OutSize]' from 'std::insert_iterator<_Container>'
with
[
_Container=std::map<std::wstring,unsigned int>
]
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm(1279) : see declaration of 'std::transform'
foo.cpp(327): error C2784: '_OutIt std::transform(_InIt1,_InIt1,_InTy (&)[_InSize],_OutIt,_Fn2)' : could not deduce template argument for '_InTy (&)[_InSize]' from 'boost::counting_iterator<Incrementable>'
with
[
Incrementable=unsigned int
]
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm(1267) : see declaration of 'std::transform'
foo.cpp(327): error C2914: 'std::transform' : cannot deduce template argument as function argument is ambiguous
and so on...
Please explain what is the problem is with compilation?
UPDATE: Thanks for answers. I realized, that it is MSVC2010 bug. By the way the line
&std::make_pair<const std::wstring&, const unsigned&>
causes the same error
This is a bug in the Visual C++ library implementation. The following program demonstrates the issue:
#include <utility>
int main()
{
&std::make_pair<int, int>;
};
This program yields the error:
error C2568: 'identifier' : unable to resolve function overload
In the C++ language specification, make_pair is not an overloaded function. The Visual C++ 2010 library implementation includes four overloads taking various combinations of lvalue and rvalue references.
While an implementation of the C++ Standard Library is allowed to add overloads for member functions, it isn't allowed to add overloads for nonmember functions, thus this is a bug.
The bug was reported and will be fixed in the next version of Visual C++. However, as STL notes in the resolution to that bug, you'll need to make the template arguments to std::make_pair lvalue references:
&std::make_pair<const std::wstring&, const unsigned&>
g++ 4.4.5 compiles it without errors. Seems to be a Visual Studio 10 defect.

Comparison operators for directory_entry are missing

Consider the following program:
#include <iostream>
#include "boost/filesystem.hpp"
int main()
{
boost::filesystem::directory_entry d("test.txt");
boost::filesystem::directory_entry e("test.txt");
if (d == e) { // <---- error C2784
std::cout << "equal" << std::endl;
}
return 0;
}
This fails to compile (Visual Studio 2005, Windows XP SP3) with 17 variations of this error:
error C2784: 'bool std::operator ==(const std::stack<_Ty,_Container> &,
const std::stack<_Ty,_Container> &)' :
could not deduce template argument for
'const std::stack<_Ty,_Container> &' from
'boost::filesystem::directory_entry'
According to the documentation (I am still using Boost 1.45), there are comparison operators defined for directory_entry, but neither me nor the compiler can find them (I checked the headers manually). Am I overlooking something? Could it be that I made a mistake when building boost, maybe by setting some option that disables these operators? Is the documentation wrong? Can anyone explain?
If you were unable to locate the operator in the header file, then maybe you have a different version of the library? In Boost 1.45, the operator is located in operations.hpp.
Ok, apparently this is only supported in the new Version of the library. Defining BOOST_FILESYSTEM_VERSION as 3 at the start of the program fixed the problem.