An old method contains code like the following (anonymised):
std::wstring wstr = ...;
std::string str(wstr.begin(), wstr.end());
Previously this all compiled without warnings but as we update to C++17 and VS2019 (v142) and tidy project settings, it now gives these big scary warnings:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2468,23): warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem', possible loss of data
with
[
_Elem=char
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
message : see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
message : see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
I am pretty sure this code pre-dates use of UNICODE in our codebase - it seems to work but I don't really understand the warnings or what I should do about it.
I found this question: UTF8 to/from wide char conversion in STL but the nice neat solution has comments saying it's deprecated in C++17! It's somewhat a mystery why this code mixes string and wstring in the first place, is there an easy solution? Or is this a case "just leave it if it works?!"
The issue is that you are converting from a 16 bit string to an 8 bit string. Since 16 bits hold more data than 8, data will then get lost. If you are converting between UTF-16 and UTF-8, you need to do it properly with a conversion library.
C++ does provide conversion library in the form of: codecvt (Deprecated in C++17 but still there for a while).
If you are sure the string only contains ASCII, you can suppress the warning.
See https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16 for details
The warning is quite clear on its own.
warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem',
possible loss of data
Which means, this line std::string str(wstr.begin(), wstr.end()) involves a type casting from wchar_t to a narrower data type const _Elem a.k.a char. Since any narrowing cast may lead to data loss, hence the warning.
Consider an example as following:
#include <cstddef>
#include <iostream>
#include <string>
int main() {
std::wstring ws{};
auto c = (wchar_t)0x41'42'43'44; // A'B'C'D in ASCII
for (int i = 0; i < 3; ++i)
ws.push_back(c);
std::string str{ws.begin(), ws.end()};
std::cout << str.c_str() << std::endl;
}
The code above run and print DDD.
On 64 bit machine, the constructor of str move 4 bytes at a time to read a wchar_t. However, string type can only accept element as char ==> the constructor must perform a narrowing cast from wchar_t to char which results in a loss of 3 byte A B C for each wchar_t element.
Related
I'm taking up some folks advice and looking into the fmt library:
http://fmtlib.net
It appears to have the features I need, and claims to support %p (pointer), but when compiling my code which uses a %p I get a long string of template errors (incomprehensible). I'll post them at the end of this.
if I pull out the %p and the corresponding pointer argument, then it compiles on VS2017 c++17.
However, I'm at a loss as to how to either decode the template errors, or to get some insight as to why it won't accept a %p argument in the first place.
I've tried casting the argument to a (void*) - same issue.
I've tried using the python style syntax in the formatter {} - same issue.
I've broken out the %p bits separately from the rest of the formatting - same issue.
I see that there is support for user-types - but in this case I just want to output this as a raw pointer value. I could just skip it, after all how valuable can the pointer address be, really? But of course that means more work during conversion from sprintf to fmt::format to hunt down all %p and "do something with them" such as elide them.
But the docs seem to indicate that %p is supported - http://fmtlib.net/latest/syntax.html (about 3/4 of the way down - search on 'pointer' or 'p').
Here's the calling function: (note: pAccels is declared as const ACCEL *)
m_hAccel = ::CreateAcceleratorTable(const_cast<LPACCEL>(pAccels), (int)count);
if (!m_hAccel)
{
auto error = GetLastError();
throw CWinAPIErrorException(__FUNCTION__, "CreateAcceleratorTable", fmt::format("%p,%u", pAccels, count), error);
}
Here's the diagnostic spewage:
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2825: 'fmt::v5::internal::get_type<Context,Arg>::value_type': must be a class or namespace when followed by '::'
1> with
1> [
1> Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>,
1> Arg=const ACCEL *
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1081): note: see reference to class template instantiation 'fmt::v5::internal::get_type<Context,Arg>' being compiled
1> with
1> [
1> Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>,
1> Arg=const ACCEL *
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1190): note: see reference to function template instantiation 'unsigned __int64 fmt::v5::internal::get_types<Context,const ACCEL*,size_t>(void)' being compiled
1> with
1> [
1> Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1190): note: while compiling class template member function 'unsigned __int64 fmt::v5::format_arg_store<fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<Char>>,Char>,const ACCEL *,size_t>::get_types(void)'
1> with
1> [
1> Char=char
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1478): note: see reference to class template instantiation 'fmt::v5::format_arg_store<fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<Char>>,Char>,const ACCEL *,size_t>' being compiled
1> with
1> [
1> Char=char
1> ]
1>c:\users\steve\source\tbx\wapi\acceleratortable.cpp(58): note: see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> fmt::v5::format<char[6],const ACCEL*,size_t,0>(const S (&),const ACCEL *const &,const size_t &)' being compiled
1> with
1> [
1> S=char [6]
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2510: 'value_type': left of '::' must be a class/struct/union
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2065: 'type_tag': undeclared identifier
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2131: expression did not evaluate to a constant
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): note: a non-constant (sub-)expression was encountered
1>c:\users\steve\source\fmt\include\fmt\core.h(1197): error C2131: expression did not evaluate to a constant
1>c:\users\steve\source\fmt\include\fmt\core.h(1082): note: failure was caused by non-constant arguments or reference to a non-constant symbol
1>c:\users\steve\source\fmt\include\fmt\core.h(1082): note: see usage of 'value'
To format a pointer you can either cast it to void*:
std::string s = fmt::format("{},{}", static_cast<void*>(pAccels), count);
or wrap it in fmt::ptr:
std::string s = fmt::format("{},{}", fmt::ptr(pAccels), count);
Working example on godbolt: https://godbolt.org/z/sCNbjr
Note that format uses Python-like format string syntax, not printf's and returns a std::string object.
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)
I get a following compiler (vs2012) error:
Error 3 error C2679: binary '+=' : no operator found which takes a
right-hand operand of type 'const std::chrono::duration<_Rep,_Period>'
(or there is no acceptable conversion) c:\program files
(x86)\microsoft visual studio 11.0\vc\include\chrono 749
My definition of duration is:
// Tick interval type in nanoseconds
typedef std::chrono::duration<double, std::ratio<1, 100000000>> tick_interval_type;
Same error when I use float... It only compiles when the Rep type of duration is integer.
Can someone please help?
Edit (more complete log from Output):
c:\program files (x86)\microsoft visual studio
11.0\vc\include\chrono(749): error C2679: binary '+=' : no operator found which takes a right-hand operand of type 'const
std::chrono::duration<_Rep,_Period>' (or there is no acceptable
conversion) with [
_Rep=double,
_Period=std::nano ] c:\program files (x86)\microsoft visual studio 11.0\vc\include\chrono(166): could be 'std::chrono::duration<_Rep,_Period>
&std::chrono::duration<_Rep,_Period>::operator +=(const
std::chrono::duration<_Rep,_Period> &)' with [
_Rep=__int64,
_Period=std::nano ] while trying to match the argument list '(std::chrono::nanoseconds, const
std::chrono::duration<_Rep,_Period>)' with [
_Rep=double,
_Period=std::nano ] c:\program files (x86)\microsoft visual studio 11.0\vc\include\thread(164) : see reference to function template instantiation 'xtime std::_To_xtime(const
std::chrono::duration<_Rep,_Period> &)' being compiled with [
_Rep=double,
_Period=std::nano ] c:\dev\projects\revolverx\classes\ticker.h(78) : see reference to function template instantiation 'void
std::this_thread::sleep_for(const
std::chrono::duration<_Rep,_Period> &)' being compiled with [
_Rep=double,
_Period=std::nano ]
<chrono> in Visual Studio is broken. It doesn't work with mixed type arithmetic, which, arguably, is one of the main features of <chrono>. You get this error because one of the sides uses __int64 nanos and the other uses double nanos.
I recommend either dropping it in favor of a real C++ implementation, or using Boost.Chrono.
Update: I've come upon this question four years after it was originally posted, and I've tested this on Visual Studio 2015. It does compile now. For example:
#include <iostream>
#include <iomanip>
#include <chrono>
int main()
{
typedef std::chrono::duration<double, std::ratio<1, 100000000>> tick_interval_type; // Originally posted line
tick_interval_type tick {0};
tick += std::chrono::microseconds(3);
std::cout << std::setprecision(6) << std::fixed << tick.count();
return 0;
}
Output:
300.000000
I got the above error on the code snippet below, I fixed this error. But I'm unsure about the fix, could you please let me know if the fix is not good. Thanks for your time!
Code Snippet:
// get length
//long length = strlen( statement)+5;
std::streamoff length = strlen(statement) + 5; // Fix for the error
// ckeck length and stream size against max buffer size
if( (m_sqlStream.tellp()+length)>=BATCH_WRITER_BUFFER_SIZE) //c2666
Output:
error C2666: 'std::fpos<_Mbstatet>::operator +' : 2 overloads have similar conversions
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\iosfwd(88): could be 'std::fpos<_Mbstatet> std::fpos<_Mbstatet>::operator +(std::streamoff) const'
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\comutil.h(174): or '_bstr_t operator +(const wchar_t *,const _bstr_t &)'
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\comutil.h(173): or '_bstr_t operator +(const char *,const _bstr_t &)'
while trying to match the argument list '(std::fpos<_Mbstatet>, long)'
I think it's right. The std::streamsize and std::streamoff are required to be typedefs of an integral type, and they can be converted to/from integral types.
The compiler complains because it can't determine which overload of operator + is appropriate since the parameters can be converted implicitly more than one way. For example:
void f(int, double);
void f(double, int);
int main() {
f(3, 4); // C2666! 3 or 4 can be converted to a int or a double, compiler can't resolve this ambiguity.
}
You can clarify it by casting one or more of the actual parameters explicitly:
if ((long)m_sqlStream.tellp() + length) >= BATCH_WRITER_BUFFER_SIZE)
or do just what you have done.
Note the compiler may warn you about possible loss of data while conversion from std::streamoff to long, it's because std::streamoff is a signed integral type defined by your C++ standard library implementation, and large enough to cater for the largest possible file sizes.
I'm using the Visual Studio 11 beta and I'm curious about a compilation error i'm getting storing a std::function object in my class.
typedef std::function<void (int, const char*, int, int, const char*)> MyCallback;
In my class I have,
MyCallback m_callback;
This compiles just fine. If I add one more argument to the list it fails.
typedef std::function<void (int, const char*, int, int, const char*, int)> MyCallback;
The failure is:
>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(535): error C2027: use of undefined type 'std::_Get_function_impl<_Tx>'
1> with
1> [
1> _Tx=void (int,const char *,int,int,const char *,int)
1> ]
1> f:\development\projects\applications\my.h(72) : see reference to class template instantiation 'std::function<_Fty>' being compiled
1> with
1> [
1> _Fty=void (int,const char *,int,int,const char *,int)
1> ]
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(536): error C2504: 'type' : base class undefined
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(539): error C2027: use of undefined type 'std::_Get_function_impl<_Tx>'
1> with
1> [
1> _Tx=void (int,const char *,int,int,const char *,int)
1> ]
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(539): error C2146: syntax error : missing ';' before identifier '_Mybase'
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(539): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
This is a dynamically linked library which is preparing data to pass to another application. I can certainly rework the format of the data so that it can be passed with fewer arguments, but I was wondering why I see this limit?
Switching back to the c-style function pointer,
typedef void (*MyCallback)(int, const char*, int, int, const char*, int);
seems to work fine.
This limit is set by the implementation in Visual Studio.
The C++ specification for std::function does not place any limit. std::function uses variadic templates to work with any number of arguments. Implementations may have a limit based on, e.g., template instantiation nesting limits, but it should be large. The spec suggests 1024 as a good minimum supported nesting depth, and 256 as a good minimum for arguments allowed in one function call, for example.
Visual Studio (as of VS11) does not have variadic templates. They simulate them up to 5 arguments in VS11, though you can change it to up to 10. Do this by defining _VARIADIC_MAX in your project. This can increase compile times greatly.
Update: The VS 2012 Nov CTP adds support for variadic templates, but the standard library has not yet been updated to use them. Once it is updated you should be able to use as many arguments as you want with std::function.