using the correct to_chars overload - c++

I'm using Clang 14 (on Apple M1), which has full support for C++ 17, and I'm trying to utilize the new to_chars function. Here's my very simple test file:
#include <charconv>
#include <iostream>
int main() {
char a[10];
double pi = 3.141592;
std::to_chars_result res = std::to_chars(a, a+10, pi);
*res.ptr = '\0';
std::cout << a << std::endl;
}
My compile command is clang -std=c++17 test_to_chars.cpp, and the output is below:
test_to_chars.cpp:8:30: error: call to deleted function 'to_chars'
std::to_chars_result res = std::to_chars(a, a+10, pi);
^~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/charconv:166:6: note: candidate function has been explicitly deleted
void to_chars(char*, char*, bool, int = 10) = delete;
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/charconv:450:1: note: candidate template ignored: requirement 'is_integral<double>::value' was not satisfied [with _Tp = double]
to_chars(char* __first, char* __last, _Tp __value)
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/charconv:458:1: note: candidate function template not viable: requires 4 arguments, but 3 were provided
to_chars(char* __first, char* __last, _Tp __value, int __base)
^
test_to_chars.cpp:8:24: error: no viable conversion from 'void' to 'std::to_chars_result'
std::to_chars_result res = std::to_chars(a, a+10, pi);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/charconv:154:25: note: candidate constructor (the implicit copy constructor) not viable: cannot convert argument of incomplete type 'void' to 'const std::to_chars_result &' for 1st argument
struct _LIBCPP_TYPE_VIS to_chars_result
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/charconv:154:25: note: candidate constructor (the implicit move constructor) not viable: cannot convert argument of incomplete type 'void' to 'std::to_chars_result &&' for 1st argument
2 errors generated.
I'm calling to_chars(char*, char*, double) but for some reason it's using an implicit conversion and trying to call to_chars(char*, char*, bool, int = 10) instead, which is a deleted function.
Is there a way for me to tell C++ that I don't want it to convert my double parameter to a bool?

I'm using Clang 14 (on Apple M1), which has full support for C++ 17
This is unfortunately not correct. While the compiler itself has full C++17 support, the stdlib of your clang version (Apple clang 14) does not implement any floating point charconv features.
See the entry "Elementary string conversions" in the cppreference table.
It is important to note that you are not running "clang 14", but "Apple clang 14". Your code snippet compiles just fine on normal clang 14.

Related

C++ map invalid conversion from int to const LexType& (which is defined by myself in fact a int)

I defined a map like this :
std::map<std::string,LexType> lexname_s = { { "PROGRAM" , PROGRAM}}
And a LexType, like this :
typedef enum
{
ENDFILE, ERROR,
PROGRAM, PROCEDURE, TYPE, VAR, IF,
} LexType;
In Visual Studio Code, it always shows error type when I touch it.
//
I add more details for what i said.
the line
std::map<std::string,LexType> lexname_s = { { "PROGRAM" , PROGRAM}}
show error . it seems i can't initialize it in this way.
I compile it in the gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) in a cloud server which is centos7.
AND the error code shows below
from parse.cpp:1:
../utils.h:52:27: error: invalid conversion from ‘int’ to ‘const LexType&’ [-fpermissive]
{"ERROR", ERROR}};
^
In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:64:0,
from /usr/include/c++/4.8.2/bits/stl_tree.h:61,
from /usr/include/c++/4.8.2/map:60,
from ../globals.h:6,
from parse.h:4,
from parse.cpp:1:
/usr/include/c++/4.8.2/bits/stl_pair.h:112:26: error: initializing argument 2 of ‘constexpr std::pair<_T1, _T2>::pair(const _T1&, const _T2&) [with _T1 = const std::basic_string<char>; _T2 = LexType]’ [-fpermissive]
_GLIBCXX_CONSTEXPR pair(const _T1& __a, const _T2& __b)```
EOF(which shows in the map define) is a reserved a macro defined in stdio.h
it's the problem of it.
change the name will be ok.

No narrowing warnings when using `emplace_back` instead of `push_back`

My colleague ran into an unexpected issue with emplace_back and I am trying to wrap my head around it. The following test.cpp is a minimal example that reproduces the issue:
#include <vector>
class A {
public:
explicit A(int /*unused*/) {}
};
int main() {
double foo = 4.5;
std::vector<A> a_vec{};
a_vec.emplace_back(foo); // No warning with Wconversion
A a(foo); // Gives compiler warning with Wconversion as expected
}
Compiling with g++ 8.3.0 yields the following warning:
$ g++ -Wconversion test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:10:10: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
A a(bar); // Gives compiler warning with Wconversion as expected
So the implicit conversion is caught when a simple object is constructed, but not when emplace_back is called.
Why is there no warning for emplace_back?
This is a consequence of how the default allocator constructs an A. When you do A a{foo, bar} you are using list initialization and a narrowing conversion is required to issue a diagnostic. With the default allocator, it uses
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
where p is a pointer to the element of the vector data and T is the value_type of the vector. Here they use parentheses instead of braces and with parentheses narrowing conversions are allowed so you don't see a diagnostic message.
If you wrote your own allocator that did
::new (static_cast<void*>(p)) T{std::forward<Args>(args)...}
Then you would get the warning.
In order to get the warning you need to compile with:
$ g++ -Wsystem-headers -Wconversion test.cpp -o test
In file included from /usr/include/c++/8/vector:60,
from test.cpp:1:
/usr/include/c++/8/bits/stl_algobase.h: In function ‘constexpr int std::__lg(int)’:
/usr/include/c++/8/bits/stl_algobase.h:1001:44: warning: conversion from ‘long unsigned int’ to ‘int’ may change value [-Wconversion]
{ return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); }
^
/usr/include/c++/8/bits/stl_algobase.h: In function ‘constexpr unsigned int std::__lg(unsigned int)’:
/usr/include/c++/8/bits/stl_algobase.h:1005:44: warning: conversion from ‘long unsigned int’ to ‘unsigned int’ may change value [-Wconversion]
{ return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); }
^
In file included from /usr/include/x86_64-linux-gnu/c++/8/bits/c++allocator.h:33,
from /usr/include/c++/8/bits/allocator.h:46,
from /usr/include/c++/8/vector:61,
from test.cpp:1:
/usr/include/c++/8/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = A; _Args = {double&}; _Tp = A]’:
/usr/include/c++/8/bits/alloc_traits.h:475:4: required from ‘static void std::allocator_traits<std::allocator<_Tp1> >::construct(std::allocator_traits<std::allocator<_Tp1> >::allocator_type&, _Up*, _Args&& ...) [with _Up = A; _Args = {double&}; _Tp = A; std::allocator_traits<std::allocator<_Tp1> >::allocator_type = std::allocator<A>]’
/usr/include/c++/8/bits/vector.tcc:103:30: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {double&}; _Tp = A; _Alloc = std::allocator<A>]’
test.cpp:9:25: required from here
/usr/include/c++/8/ext/new_allocator.h:136:4: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
The warning is no longer as clear, since it happens in a system header. Note that it is not enough to only use the -Wsystem-headers flag, one needs both -Wsystem-headers and -Wconversion to catch this.
In the case of push_back it is enough to use -Wnarrowing to get a warning.

C++ on MacOS: show date and time issue

I bought a MacBook Pro and I've been using MacOS for the past two days. I've been trying to write this C++ code that outputs the date and time using chrono and ctime libraries.
This code was working just fine on my Windows machine and my CentOS7 server. However, on my MacBook Pro it fails to compile.
This is the error message I get when I try to compile with G++:
main.cpp:19:61: error: no viable conversion from 'time_point<std::__1::chrono::steady_clock,
duration<[...], ratio<[...], 1000000000>>>' to 'const
time_point<std::__1::chrono::system_clock, duration<[...], ratio<[...], 1000000>>>'
std::time_t date = std::chrono::system_clock::to_time_t(now);
^~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1340:28: note: candidate constructor
(the implicit copy constructor) not viable: no known conversion from
'std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long,
std::__1::ratio<1, 1000000000> > >' to 'const
std::__1::chrono::time_point<std::__1::chrono::system_clock, std::__1::chrono::duration<long long,
std::__1::ratio<1, 1000000> > > &' for 1st argument
class _LIBCPP_TEMPLATE_VIS time_point
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1340:28: note: candidate constructor
(the implicit move constructor) not viable: no known conversion from
'std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long,
std::__1::ratio<1, 1000000000> > >' to 'std::__1::chrono::time_point<std::__1::chrono::system_clock,
std::__1::chrono::duration<long long, std::__1::ratio<1, 1000000> > > &&' for 1st argument
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1359:5: note: candidate template
ignored: could not match 'std::__1::chrono::system_clock' against 'std::__1::chrono::steady_clock'
time_point(const time_point<clock, _Duration2>& t,
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1566:53: note: passing argument to
parameter '__t' here
static time_t to_time_t (const time_point& __t) _NOEXCEPT;
^
1 error generated.
basavyr#Roberts-MacBook-Pro simpleTest %
Here is the code:
void getTime()
{
auto now = std::chrono::high_resolution_clock::now();
std::time_t date = std::chrono::system_clock::to_time_t(now);
std::cout << std::ctime(&date);
}
int main()
{
getTime();
}
I assume the issue has to do with the fact that MacOS is using CLANG compiler?
Any ideas how can I solve this?
Thank you!
Your code is only likely to work when std::high_resolution_clock is the same type as std::system_clock. There is no guarantee that time points from different clocks are the same or convertible.
For conversion to time_t which only has seconds resolution system_clock will be perfectly adequate:
void getTime()
{
auto now = std::chrono::system_clock::now();
std::time_t date = std::chrono::system_clock::to_time_t(now);
std::cout << std::ctime(&date);
}
int main()
{
getTime();
}

Why does this use of boost::none fail to compile with nvcc?

I'm trying to compile the following code:
#include <boost/optional.hpp>
void foo(boost::optional<unsigned> x = boost::none);
placed in the file a.cu, with the CUDA compiler, using the following command line:
nvcc a.cu -c --std=c++11 -I/opt/boost/include
but I get a bunch of errors:
a.cu:2:53: error: conversion from ‘const boost::none_t(boost::none_t::init_tag (*)())’ to ‘boost::optional<unsigned int>’ is ambiguous
void foo(boost::optional<unsigned> x = boost::none);
^
/opt/boost/include/boost/optional/optional.hpp:805:1: note: candidate: boost::optional<T>::optional(boost::optional<T>::rval_reference_type) [with T = unsigned int; boost::optional<T>::rval_reference_type = unsigned int&&] <near match>
optional ( rval_reference_type val ) : base( boost::forward<T>(val) )
^ ~~~~
/opt/boost/include/boost/optional/optional.hpp:805:1: note: conversion of argument 1 would be ill-formed:
a.cu:2:53: error: invalid conversion from ‘const boost::none_t (*)(boost::none_t::init_tag (*)())’ to ‘unsigned int’ [-fpermissive]
void foo(boost::optional<unsigned> x = boost::none);
^
/opt/boost/include/boost/optional/optional.hpp:800:1: note: candidate: boost::optional<T>::optional(boost::optional<T>::argument_type) [with T = unsigned int; boost::optional<T>::argument_type = const unsigned int&] <near match>
optional ( argument_type val ) : base(val) {}
^ ~~~~
/opt/boost/include/boost/optional/optional.hpp:800:1: note: conversion of argument 1 would be ill-formed:
a.cu:2:53: error: invalid conversion from ‘const boost::none_t (*)(boost::none_t::init_tag (*)())’ to ‘unsigned int’ [-fpermissive]
void foo(boost::optional<unsigned> x = boost::none);
Why does this happen, and can I circumvent the problem while still actually using boost::optional in (host-side) code compiled with nvcc?
Additional information:
The code compiles fine with g++ 6.3.0 (my distribution's compiler).
This code (or rather, similar code) used to compile and work on an earlier Linux distribution I was using, where the compiler was g++ 5.4.x .
I've tried this with Boost versions 1.65.1 and 1.69.0 .
I've tried this with CUDA versions 9.2.88 and 10.0.130 .
I had the exact same error and was able to get this to work with this modification:
#define BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE
#include <boost/optional.hpp>
This is using CUDA 10.0.130, g++ 7.3.0, and Boost 1.68.0.
A partial answer to the second question:
You could consider using Andrzej Krzemieński's neat and self-contained implementation of an optional instead of boost::optional. It works with C++11, which is what you seem to be doing.

filesystem::path constructor call fails

This code does not compile, using Boost 1.48 and GCC:
// const char* left, const char* right
boost::filesystem::path p = boost::filesystem::absolute(
boost::filesystem::path(right, boost::filesystem::native), // line 314
boost::filesystem::path(left, boost::filesystem::native) ); // line 315
Error messages:
LoggerImplementation.cpp|314|error: invalid conversion from ‘bool (*)(const std::string&)’ to ‘void*’
LoggerImplementation.cpp|314|error: initializing argument 2 of ‘boost::filesystem3::path::path(const Source&, typename boost::enable_if<boost::filesystem3::path_traits::is_pathable<typename boost::decay<Source>::type>, void>::type*) [with Source = const char*]’
LoggerImplementation.cpp|315|error: invalid conversion from ‘bool (*)(const std::string&)’ to ‘void*’
LoggerImplementation.cpp|315|error: initializing argument 2 of ‘boost::filesystem3::path::path(const Source&, typename boost::enable_if<boost::filesystem3::path_traits::is_pathable<typename boost::decay<Source>::type>, void>::type*) [with Source = const char*]’
Under MSVC it compiles. How can I fix this?
Your second argument (boost::filesystem::native) is wrong. boost::filesystem::path simply doesn’t have a constructor which takes this argument – leave it off and the code compiles.
In fact, boost::filesystem::native is a function, and using it in the manner you tried makes no sense. Furthermore, if MSVC compiles this code, that’s a definitive bug (it is using an implicit conversion from a function pointer to void*, which doesn’t exist according to the standard).