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.
Related
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))};
The GNU MP manual specifies the declaration of the function get_mpz_t:
Function: mpz_t mpz_class::get_mpz_t ()
So I was expecting a mpz_t return type. But running the simple code:
#include <iostream>
#include <gmpxx.h>
using namespace std;
int main (void) {
mpz_class n;
n = "12345678901234567890123456789012345678901234567890";
mpz_t m;
mpz_init(m);
m = n.get_mpz_t();
gmp_printf("m %Zd\n", m);
}
Compiled with
g++ mpz_test.cc -o mpz_test -lgmpxx -lgmp
Produces the error output at line m = n.get_mpz_t():
mpz_split.cc: In function ‘int main()’:
mpz_split.cc:12:4: error: incompatible types in assignment of ‘mpz_ptr {aka __mpz_struct*}’ to ‘mpz_t {aka __mpz_struct [1]}’
m = n.get_mpz_t();
^
Looking at the gmpxx.h code I find the declarations:
// conversion functions
mpz_srcptr __get_mp() const { return mp; }
mpz_ptr __get_mp() { return mp; }
mpz_srcptr get_mpz_t() const { return mp; }
mpz_ptr get_mpz_t() { return mp; }
And, of course, mpz_ptr is defined in gmp.h
typedef __mpz_struct *mpz_ptr;
So, is the manual inaccurate? Or, what am I doing wrong here?
The problem occurs on this line:
m = n.get_mpz_t();
You cannot assign to mpz_t directly, instead use mpz_set():
mpz_set(m, n.get_mpz_t());
So, your code should look like this:
#include <iostream>
#include <gmpxx.h>
using namespace std;
int main (void) {
mpz_class n;
n = "12345678901234567890123456789012345678901234567890";
mpz_t m;
mpz_init(m);
mpz_set(m, n.get_mpz_t()); // correct assignment
gmp_printf("m %Zd\n", m);
}
I would like to write a function that wraps MPI_Allreduce, and which accepts any binary operator (as std::reduce) to be used as reduction operator by MPI. Especially, the user of such a function could use a lambda.
The following simple sample code illustrates that:
#include <mpi.h>
#include <iostream>
#include <functional>
template<typename BinaryOp>
void reduce(double *data, int len, BinaryOp op) {
auto lambda=[op](void *a, void *b, int *len, MPI_Datatype *){
double *aa=static_cast<double *>(a);
double *bb=static_cast<double *>(bb);
for (int i=0; i<*len; ++i) {
bb[i]=op(aa[i], bb[i]);
}
};
// MPI_User_function is a typedef to: void (MPI_User_function) ( void * a, void * b, int * len, MPI_Datatype * )
MPI_User_function *opPtr=/* black magic code that get the function pointer from the lambda */;
MPI_Op mpiOp;
MPI_Op_create(*opPtr, 1, &mpiOp);
MPI_Allreduce(MPI_IN_PLACE, data, len, MPI_DOUBLE, mpiOp, MPI_COMM_WORLD);
MPI_Op_free(&mpiOp);
}
int main() {
MPI_Init(nullptr, nullptr);
double data[4]={1.,2.,3.,4.};
reduce(data, 4, [](double a, double b){return a+b;});
int pRank;
MPI_Comm_rank(MPI_COMM_WORLD, &pRank);
if (pRank==0) {
for (int i=0; i<4; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
MPI_Finalize();
return 1;
}
The missing part is the code that get a function pointer from the lambda in the reduce function. From several related questions, this problem of getting a function pointer from a capturing lambda seems to be tricky but possible to solve. But I failed to have something working on this simple code (I tried some tricks with std::function, std::bind, storage of the lambda in a static variable)... So a little help would be great!
EDIT: Following #noma answer, I tried the following simplified code without MPI in goldbolt
#include <iostream>
#include <functional>
typedef double MPI_Datatype;
template<typename BinaryOp, BinaryOp op> // older standards
void non_lambda(void *a, void *b, int *len, MPI_Datatype *)
{}
template<typename BinaryOp>
void reduce(double *data, int len, BinaryOp op) {
typedef void (MPI_User_function) ( void * a, void * b, int * len, MPI_Datatype * );
MPI_User_function *opPtr = &non_lambda<decltype(+op), +op>; // older standards;
}
int main() {
double data[4]={1.,2.,3.,4.};
reduce(data, 4, [](double a, double b){return a+b;});
return 1;
}
It compile on some compilers. Here are the results:
icc >= 19.0.1 (with -std=c++17) : OK
clang++ >= 5.0.0 (with --std=c++17): OK
clang++ 10.0.0 (with --std=c++14): NOK
g++ 9.3 (with --std=c++17): NOK
icc >= 19.0.0 (with -std=c++17) : NOK
The error message with icc 19.0.0 with -std=c++17 (or icc 19.0.1 with -std=c++14) is interesting:
<source>(15): error: expression must have a constant value
MPI_User_function *opPtr = &non_lambda<decltype(+op), +op>; // older standards;
^
detected during instantiation of "void reduce(double *, int, BinaryOp) [with BinaryOp=lambda [](double, double)->double]" at line 21
And indeed, I don't really understand the passing of the 'op' variable which is a runtime argument of the function reduce as the second template parameter of the non_lambda function... Is it an obscure c++17 functionality that only some of the compilers support?
I think the lambda approach is not possible here as it is a capturing lambda, see
https://stackoverflow.com/a/28746827/7678171
We can use a function template with the BinaryOp as a template value parameter instead of a Lambda here. This assumes that the BinaryOp is either a function pointer, or a capture-less lambda, that can be converted into one. Instead of the lambda inside your reduce we introduce:
template<auto op> // this is C++17, so use --std=c++17
// template<typename BinaryOp, BinaryOp op> // older standards
void non_lambda(void *a, void *b, int *len, MPI_Datatype *)
{
double *aa=static_cast<double *>(a);
double *bb=static_cast<double *>(bb);
for (int i=0; i<*len; ++i) {
bb[i]=op(aa[i], bb[i]);
}
}
The Black Magic line then is:
/* black magic code that get the function pointer from the lambda */
MPI_User_function *opPtr = &non_lambda<+op>; // NOTE: the + implies the lamda to function pointer conversion here
// MPI_User_function *opPtr = &non_lambda<decltype(+op), +op>; // older standards;
Hope this helps.
NOTE: I got this compiled using Clang 6.0, but g++ 7.5 failed (possible compiler bug?):
error: no matches converting function ‘non_lambda’ to type ‘void (*)(void*, void*, int*, struct ompi_datatype_t**)’
MPI_User_function *opPtr = &non_lambda<+op>;
^~~~~
note: candidate is: template<auto op> void non_lambda(void*, void*, int*, ompi_datatype_t**)
void non_lambda(void *a, void *b, int *len, MPI_Datatype *)
Maybe newer g++ versions work.
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.
I'm trying to use both sort and qsort to sort a c-style string and them see which of them is better, so I've written this code, but it is not working , so can you please tell me what is wrong with it.
thanks in advance.
#include <iostream>
#include<vector>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<chrono>
#include<string>
#include<sstream>
using namespace std;
using namespace std::chrono;
void bvect(vector<double> &vec, int num)
{
auto gen = bind(normal_distribution<double>(15,4.0),default_random_engine());
for(int i=0; i<num; ++i)
vec.push_back(gen());
}
char* converttostring(int number)
{
stringstream ss;
ss << number;
return (ss.c_str());
}
int cst_cmp(const void *one, const void *two)
{
char a = *((char*)one);
char b = *((char*)two);
return strcmp(a, b);
}
//Generated random strings
void textvect(vector<string> &vec, int num)
{
srand(time(NULL));
for(int i=0; i<num; ++i)
vec.push_back(converttostring(rand()%num +1));
}
void displayvector(vector<char*>vect)
{
for (int i=0; i<vect.size(); ++i){
for (int j=0; j<strlen(vect[i]); ++j)
cout<<vect[i][j];
cout<<endl;
}
}
int main(){
int sz=100000;
vector<char*>text1, text2;
textvect(text1, sz);
text2.resize(text1.size());
copy(text1.begin(),text1.end(),text2.begin());
// qsort() string
auto t1 = system_clock::now();
qsort(&text1[0], text1.size(), sizeof(char*), cst_cmp);
auto t2 = system_clock::now();
auto dms = duration_cast<milliseconds>(t2-t1);
cout << "string qsort() took " << dms.count() << " milliseconds\n";
// sort() string
auto t3 = system_clock::now();
std::sort(text2.begin(), text2.end());
auto t4 = system_clock::now();
auto dms1 = duration_cast<milliseconds>(t4-t3);
cout << "string sort() took " << dms1.count() << " milliseconds\n";
return 0;
}
For std::sort, you are just using the default comparator, which will just compare pointer values. You need to pass a comparator that does a proper comparison (using strcmp, for example):
std::sort(text2.begin(), text2.end(),
[](const char* lhs, const char* rhs) { return strcmp(lhs,rhs) < 0; });
That's one problem, there may be others.
One problem is in your compare function for qsort:
int cst_cmp(const void *one, const void *two)
{
char a = *((char*)one);
char b = *((char*)two);
return strcmp(a, b);
}
You are not comparing strings here, because a and b are just chars. You might as well avoid them:
int cst_cmp(const void *one, const void *two)
{
return (strcmp(*(char **)one, *(char **)two));
}
These are the errors I obtain trying to compile your code:
> g++ main.cc -std=c++0x
main.cc: In function ‘char* converttostring(int)’:
main.cc:24:15: error: ‘std::stringstream’ has no member named ‘c_str’
main.cc: In function ‘int cst_cmp(const void*, const void*)’:
main.cc:31:23: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
/usr/include/string.h:143:12: error: initializing argument 1 of ‘int strcmp(const char*, const char*)’ [-fpermissive]
main.cc:31:23: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
/usr/include/string.h:143:12: error: initializing argument 2 of ‘int strcmp(const char*, const char*)’ [-fpermissive]
main.cc: In function ‘int main()’:
main.cc:55:23: error: invalid initialization of reference of type ‘std::vector<std::basic_string<char> >&’ from expression of type ‘std::vector<char*>’
main.cc:35:6: error: in passing argument 1 of ‘void textvect(std::vector<std::basic_string<char> >&, int)’
24:15 c_str() is a member function of string not of stringstream. See here.
31:23 strcmp() wants two const char * not two char. See here.
55:23 and 35:6 char* is not the same type as string.
This function isn't working
char* converttostring(int number)
{
stringstream ss;
ss << number;
return (ss.c_str());
}
and if it was sort of fixed (ss.str().c_str()), it would return a pointer to a temporary.
If you have a compiler with some C++11 support, you can use std::to_string from the standard library. Otherwise, change the return type to std::string (no pointer!).
Ask Stroustrup ;) just allocate space for the C string array and enter characters ino it.. remember to deallocate it..