Error narrow conversion when used with auto - c++

Getting error in use of auto for the implicit conversion.
Capturing the return of v.size() using int variable is ok but auto complains.
Compiler error does inform it is because of narrowing conversion .But I would like to understand in terms memory how this happens and why auto is not allowing it do that whereas normal conversion is ok
#include <iostream>
#include <vector>
int main()
{
auto v = std::vector<int>{ 1, 2, 3 };
auto c = 'h';
auto n2 = int{c};
std::cout<<n2<<" "<<c;
auto size = int{v.size()};
std::cout<<size;
int size_1 = v.size();
std::cout<<size_1;
}
Error because of below line
auto size = int{v.size()};
main.cpp: In function 'int main()': main.cpp:11:27: error: narrowing
conversion of 'v.std::vector::size()' from
'std::vector::size_type {aka long unsigned int}' to 'int' inside
{ } [-Wnarrowing]
When that line is commented it works perfectly
#include <iostream>
#include <vector>
int main()
{
auto v = std::vector<int>{ 1, 2, 3 };
auto c = 'h';
auto n2 = int{c};
std::cout<<n2<<" "<<c;
//auto size = int{v.size()};
//std::cout<<size;
int size_1 = v.size();
std::cout<<size_1;
}
Output
104 h3
DEMO LINK

This has nothing to do with auto. You will get the same warning if you use
int size = int{v.size()};
The issue here is int{v.size()} is using braced initialization to initialize a temporary int. A narrowing conversion in braced initialization is what causes the diagnostic to be displayed.
Do note that
int size_1 = v.size();
Is also a narrowing conversion, it is just not one where the standard mandates that a warning/error be emitted.

Related

Idiomatically convert signed to unsigned types if you know that value will be positive

Compare the following code. It's clear from the context that one pointer will always be bigger than the other and the result of std::distance() therefore positive. How do I idiomatically convert from signed to unsigned then without having the compiler complains about narrowing?
Demo
#include <cstdio>
#include <iterator>
#include <string_view>
#include <cstring>
std::string_view foo(const char* token)
{
const char* first = std::strchr(token, 'H');
const char* second = std::strchr(first+1, 'W');
return std::string_view { first, std::distance(first, second) }; // <-- line in question
}
int main()
{
const char* hello = "Hello World!";
const auto view = foo(hello);
printf("%.*s\n", static_cast<int>(view.size()), view.data());
}
Warning:
<source>: In function 'std::string_view foo(const char*)':
<source>:10:51: warning: narrowing conversion of 'std::distance<const char*>(first, second)' from 'std::iterator_traits<const char*>::difference_type' {aka 'long int'} to 'std::basic_string_view<char>::size_type' {aka 'long unsigned int'} [-Wnarrowing]
10 | return std::string_view { first, std::distance(first, second) };
|
~~~~~~~~~~~~~^~~~~~~~~~~~~~~
The reason you get this error is because you are using list initialization an in that context a narrowing conversion is an error. There are a couple ways to fix this. You can switch from
return std::string_view { first, std::distance(first, second) };
to
return std::string_view(first, std::distance(first, second));
which means you no longer have list initialization and narrowing is no longer considered an error or you can be explicit and use static_cast like
return std::string_view{first, static_cast<std::size_t>(std::distance(first, second))};

"result type must be constructible from value type of input range" when creating a std::vector

I have a class member that looks like this
class Controller {
protected:
// other stuff
std::vector<Task<event_t, stackDepth>> taskHandlers;
//some more stuf
}
The Task class is non-defaultConstructible, non-copyConstructible, non-copyAssignable but is moveConstructible and moveAssignable. Everything I could read (notably, std::vector documentation) leads me to think that this should compile, but the error list looks like this (full output here) :
/usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion failed: result type must be constructible from value type of input range
127 | static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
| ^~~~~
Making Task defaultConstructible did not help. The error points to the definition of the class Controller. I am using GCC 9.3.0 in c++17 mode. Did I do anything wrong ?
My best guess, given the current information, is that you messed up the move constructor syntax somehow - working example using just emplace_back:
The below compiles fine, link to godbolt:
#include <vector>
class X
{
public:
X(int i) : i_(i){}
X() = delete;
X(const X&) = delete;
X(X&&) = default;//change this to 'delete' will give a similar compiler error
private:
int i_;
};
int main() {
std::vector<X> x;
x.emplace_back(5);
}
to reproduce the error result type must be constructible from value type of input range
godbolt
#include <vector>
#include <string>
#include <iostream>
int main() {
typedef std::vector<std::string> StrVec;
StrVec s1("a", "b"); // error
// stl_uninitialized.h:127:7: error: static_assert failed due to requirement 'is_constructible<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, const char &>::value' "result type must be constructible from value type of input range"
//StrVec s2("a", "b", "c"); // error
// error: no matching constructor for initialization of 'StrVec' (aka 'vector<basic_string<char> >')
StrVec s3({"a", "b"}); // ok
StrVec s4({"a", "b", "c"}); // ok
typedef std::vector<int> IntVec;
IntVec i1(1, 2); // silent error
for (auto i : i1) {
std::cout << "i = " << i << '\n';
}
// silent error:
// output:
// i = 2
// expected:
// i = 1
// i = 2
//IntVec i2(1, 2, 3); // error
// error: no matching constructor for initialization of 'IntVec' (aka 'vector<int>')
IntVec i3({1, 2}); // ok
IntVec i4({1, 2, 3}); // ok
}

Variadic function int to size_t warning

I have a function accept multiple arguments.
#include <iostream>
#include <cstdarg>
#include <vector>
using namespace std;
template<typename... Values>
void doSomething(size_t input, Values... inputs)
{
size_t len = sizeof...(Values) + 1;
size_t vals[] = {input, inputs...};
vector<size_t> n(len);
std::copy( vals, vals+len, n.data() );
for(size_t i=0; i<len; i++) cout<<n[i]<<endl;
//Do something with n vector
}
It works fine when I call this function by:
size_t a(1), b(2), c(3);
doSomething(a,b,c);
However, it will have a problem when I call this function by:
doSomething(1,2,3);
It will give out warning message:
warning: narrowing conversion of ‘inputs#0’ from ‘int’ to ‘size_t {aka long unsigned int}’ inside { } [-Wnarrowing]
size_t vals[] = {inputs...};
I do not like this warning message, is there a way to solve this problem? I would like the function to be able to accept either size_t or int. Thank you.

tail_quantile "has initializer but incomplete type"

I wrote below simple program following boost 1.55 document
#include <boost/accumulators/statistics/tail_quantile.hpp>
using namespace boost::accumulators;
void testTailQuantile()
{
// tolerance in %
double epsilon = 1;
std::size_t n = 100000; // number of MC steps
std::size_t c = 10000; // cache size
typedef accumulator_set<double, stats<tag::tail_quantile<boost::accumulators::left> > > accumulator_t_left;
accumulator_t_left acc1(boost::accumulators::tail<boost::accumulators::left>::left_tail_cache_size = c);
}
But I got below errors:
In file included from ../src/LearnBoost.cpp:16:0:
../src/testBoostAccumulator.h: In function ‘void testTailQuantile()’:
../src/testBoostAccumulator.h:23:47: error: variable
‘accumulator_t_left acc1’ has initializer but incomplete type
accumulator_t_left
acc1(boost::accumulators::tail::left_tail_cache_size
= c);
^ ../src/testBoostAccumulator.h:23:77: error: expected
primary-expression before ‘>’ token accumulator_t_left
acc1(boost::accumulators::tail::left_tail_cache_size
= c);
So frustrated at Boost. Excellent framework, but makes life very difficult...

Invalid conversion from 'int*' to 'int'

This doesn't work. Can anyone tell why?
#include <iostream>
using namespace std;
int mean( int );
int main() {
int array[] = {43, 5, 3, 5, 2};
cout << mean(array);
}
int mean( int list[] ) {
return list[0];
}
These are the errors I'm getting:
Invalid conversion from 'int*' to 'int'
Initializing argument 1 of 'int mean(int)'
You are forward declaring the mean function using a different signature. Fix your forward declaration:
int mean( int[] );
You're missing the brakets in your prototype. Try this:
int mean(int[]);