The purpose of this program is to read in data and then print out sorted data based on a few criteria.
I can get my program to compile and print out data when entering g++ -std=c++11 -o testexe assign4.cc amenity.cc but when I create a make file to do the same thing it gives out these errors:
z1755294#hopper:~/assign4$ make
g++ -c amenity.cc
amenity.cc: In function ‘std::istream& operator>>(std::istream&, Amenity&)’:
amenity.cc:52:21: error: ‘stoi’ was not declared in this scope
am.id = stoi(tmp); // from_string_to< int >(tmp);
^
amenity.cc:61:31: error: ‘stof’ was not declared in this scope
am.avg_Jan_temp = stof(tmp); // from_string_to< float >(tmp);
^
amenity.cc: In function ‘float get_avg(const ListFlt&)’:
amenity.cc:176:24: warning: lambda expressions only available with -std=c++11 or -std=gnu++11
{ return init += val; });
^
amenity.cc:176:25: error: no matching function for call to ‘accumulate(std::vector<float>::const_iterator, std::vector<float>::const_iterator, double&, get_avg(const ListFlt&)::<lambda(double&, float)>)’
{ return init += val; });
^
amenity.cc:176:25: note: candidates are:
In file included from /usr/include/c++/4.9/numeric:62:0,
from Amenity.h:10,
from amenity.cc:1:
/usr/include/c++/4.9/bits/stl_numeric.h:146:5: note: template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation)
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init,
^
/usr/include/c++/4.9/bits/stl_numeric.h:146:5: note: template argument deduction/substitution failed:
amenity.cc: In substitution of ‘template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator<const float*, std::vector<float> >; _Tp = double; _BinaryOperation = get_avg(const ListFlt&)::<lambda(double&, float)>]’:
amenity.cc:176:25: required from here
amenity.cc:176:25: error: template argument for ‘template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation)’ uses local type ‘get_avg(const ListFlt&)::<lambda(double&, float)>’
{ return init += val; });
^
amenity.cc:176:25: error: trying to instantiate ‘template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation)’
In file included from /usr/include/c++/4.9/numeric:62:0,
from Amenity.h:10,
from amenity.cc:1:
/usr/include/c++/4.9/bits/stl_numeric.h:120:5: note: template<class _InputIterator, class _Tp> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp)
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
^
/usr/include/c++/4.9/bits/stl_numeric.h:120:5: note: template argument deduction/substitution failed:
amenity.cc:176:25: note: candidate expects 3 arguments, 4 provided
{ return init += val; });
^
amenity.cc: In function ‘float get_sd(const ListFlt&, float)’:
amenity.cc:188:44: warning: lambda expressions only available with -std=c++11 or -std=gnu++11
{ return init += (val - avg)*(val - avg); });
^
amenity.cc:188:45: error: no matching function for call to ‘accumulate(std::vector<float>::const_iterator, std::vector<float>::const_iterator, float&, get_sd(const ListFlt&, float)::<lambda(float&, float)>)’
{ return init += (val - avg)*(val - avg); });
^
amenity.cc:188:45: note: candidates are:
In file included from /usr/include/c++/4.9/numeric:62:0,
from Amenity.h:10,
from amenity.cc:1:
/usr/include/c++/4.9/bits/stl_numeric.h:146:5: note: template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation)
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init,
^
/usr/include/c++/4.9/bits/stl_numeric.h:146:5: note: template argument deduction/substitution failed:
amenity.cc: In substitution of ‘template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator<const float*, std::vector<float> >; _Tp = float; _BinaryOperation = get_sd(const ListFlt&, float)::<lambda(float&, float)>]’:
amenity.cc:188:45: required from here
amenity.cc:188:45: error: template argument for ‘template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation)’ uses local type ‘get_sd(const ListFlt&, float)::<lambda(float&, float)>’
{ return init += (val - avg)*(val - avg); });
^
amenity.cc:188:45: error: trying to instantiate ‘template<class _InputIterator, class _Tp, class _BinaryOperation> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation)’
In file included from /usr/include/c++/4.9/numeric:62:0,
from Amenity.h:10,
from amenity.cc:1:
/usr/include/c++/4.9/bits/stl_numeric.h:120:5: note: template<class _InputIterator, class _Tp> _Tp std::accumulate(_InputIterator, _InputIterator, _Tp)
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
^
/usr/include/c++/4.9/bits/stl_numeric.h:120:5: note: template argument deduction/substitution failed:
amenity.cc:188:45: note: candidate expects 3 arguments, 4 provided
{ return init += (val - avg)*(val - avg); });
^
amenity.cc: In function ‘void print_top_bottom_n(ListA&, int, int)’:
amenity.cc:257:19: error: ISO C++ forbids declaration of ‘am’ with no type [-fpermissive]
for (const auto &am : vecA)
^
amenity.cc:257:24: error: range-based ‘for’ loops are not allowed in C++98 mode
for (const auto &am : vecA)
^
amenity.cc:262:10: error: no match for call to ‘(PrintIt) (const int&)’
prt(am);
^
In file included from amenity.cc:1:0:
Amenity.h:69:7: note: candidate is:
class PrintIt
^
amenity.cc:195:6: note: void PrintIt::operator()(const Amenity&)
void PrintIt::operator () (const Amenity& am)
^
amenity.cc:195:6: note: no known conversion for argument 1 from ‘const int’ to ‘const Amenity&’
amenity.cc:270:10: error: no match for call to ‘(PrintIt) (const int&)’
prt(am);
^
In file included from amenity.cc:1:0:
Amenity.h:69:7: note: candidate is:
class PrintIt
^
amenity.cc:195:6: note: void PrintIt::operator()(const Amenity&)
void PrintIt::operator () (const Amenity& am)
^
amenity.cc:195:6: note: no known conversion for argument 1 from ‘const int’ to ‘const Amenity&’
Makefile:19: recipe for target 'amenity.o' failed
make: *** [amenity.o] Error 1
I have attached my source code and header files.
assign4.cc
#include "Amenity.h" //include iostream and string //
#include <fstream>
using std::string;
using std::cout;
using std::cin;
using std::ifstream;
using std::flush;
using std::cerr;
string takeInString( const string& msg = "" )
{
string val;
cout << msg << flush;
getline( cin, val );
return val;
}
int takeInChr( const string& msg = "" )
{
string reply = takeInString( msg );
if( reply.size() )
return reply[0];
// else ...
return 0;
}
bool more() //open more files //
{
if( tolower( takeInChr( "Do you want to open another file (y/n) ? " )) == 'n' )
return false;
// else ...
return true;
}
bool load_from( const char* fname, ListA& vec )
{
ifstream fin( fname );
if( fin )
{
Amenity tmp;
while( fin >> tmp )
vec.push_back( tmp );
fin.close();
return true;
}
// else
cerr << "There was a problem opening file " << fname
<< endl;
cin.get();
return false;
}
int main()
{
do
{
string name = takeInString( "Enter file name: " );
// attempt to find and open file to read it ... //
ListA vecA;
if( load_from(name.c_str(), vecA) )
{
cout << "There were " << vecA.size()
<< " records in file " << name
<< '\n';
cout << "Setting scores ... " << flush;
set_scores( vecA );
cout << "done!\n";
for( int choice = 1; choice <= 7; ++ choice )
print_top_bottom_n( vecA, choice, 10 );
}
}
while( more() );
}
amenity.cc
#include "Amenity.h"
using std::cout;
using std::string;
using std::istream;
using std::istringstream;
using std::ostream;
using std::accumulate;
const string Amenity::HEADERS[] =
{
"",
"Avg January Temperature (F)", "Avg Total January Sunshine (Hours)",
"Avg July Temperature (F)", "Avg July Humidity (%)",
"Avg Landform Topo Code 1 to 21", "Area Land Next to Water (%)",
"Composite Score"
};
// default ctor //
Amenity::Amenity() : id(-1),
avg_Jan_temp(-999), avg_hrs_tot_Jan_sun(-999),
avg_Jul_temp(-999), avg_Jul_humidity(-999),
avg_landform_topo_code_1_21(-1), percent_area_next_to_water(-999),
score(0) {}
string Amenity::get_state() const { return state; }
string Amenity::get_county() const { return county; }
float Amenity::get_avg_Jan_temp() const { return avg_Jan_temp; }
float Amenity::get_avg_hrs_tot_Jan_sun() const { return avg_hrs_tot_Jan_sun; }
float Amenity::get_avg_Jul_temp() const { return avg_Jul_temp; }
float Amenity::get_avg_Jul_humidity() const { return avg_Jul_humidity; }
int Amenity::get_avg_landform_topo_code_1_21() const { return avg_landform_topo_code_1_21; }
float Amenity::get_percent_area_next_to_water() const { return percent_area_next_to_water; }
float Amenity::get_score() const { return score; }
// definition of overload operator >> for Amenity objects ...
istream& operator >> (istream& is, Amenity& am)
{
string line;
getline(is, line);
istringstream iss(line);
for (int i = 0; i < 9; ++i)
{
string tmp;
if (getline(iss, tmp, ',')) // file here is COMMA separated, 22 fields on a line //
{
switch (i) // picking off the fields of interest //
{
case 0:
am.id = stoi(tmp); // from_string_to< int >(tmp);
break;
case 1:
am.state = tmp;
break;
case 2:
am.county = tmp;
break;
case 3:
am.avg_Jan_temp = stof(tmp); // from_string_to< float >(tmp);
break;
case 4:
am.avg_hrs_tot_Jan_sun = stof(tmp); // from_string_to< float >(tmp);
break;
case 5:
am.avg_Jul_temp = stof(tmp); // from_string_to< float >(tmp);
break;
case 6:
am.avg_Jul_humidity = stof(tmp); // from_string_to< float >(tmp);
break;
case 7:
am.avg_landform_topo_code_1_21 = stoi(tmp); // from_string_to< int >(tmp);
break;
case 8:
am.percent_area_next_to_water = stof(tmp); // from_string_to< float >(tmp);
}
}
}
return is;
}
// definition of overload operator << for Amenity objects ...
ostream& operator << (ostream& os, const Amenity& am)
{
return os << am.id << ", " << am.state << ", " << am.county << ", "
<< am.avg_Jan_temp << ", " << am.avg_hrs_tot_Jan_sun << ", "
<< am.avg_Jul_temp << ", " << am.avg_Jul_humidity << ", "
<< am.avg_landform_topo_code_1_21 << ", " << am.percent_area_next_to_water;
}
// HIGHER is 'better' ...
bool cmpJanTemp(const Amenity& a, const Amenity& b)
{
return b.get_avg_Jan_temp() < a.get_avg_Jan_temp();
}
bool cmpJanSunHrs(const Amenity& a, const Amenity& b)
{
return b.get_avg_hrs_tot_Jan_sun() < a.get_avg_hrs_tot_Jan_sun();
}
// LOWER is better ...
bool cmpJulTemp(const Amenity& a, const Amenity& b)
{
return a.get_avg_Jul_temp() < b.get_avg_Jul_temp();
}
bool cmpJulHumidity(const Amenity& a, const Amenity& b)
{
return a.get_avg_Jul_humidity() < b.get_avg_Jul_humidity();
}
// HIGHER is 'better' ...
bool cmpTopoCode(const Amenity& a, const Amenity& b)
{
return b.get_avg_landform_topo_code_1_21() < a.get_avg_landform_topo_code_1_21();
}
bool cmpPartNearWater(const Amenity& a, const Amenity& b)
{
return b.get_percent_area_next_to_water() < a.get_percent_area_next_to_water();
}
bool cmpScore(const Amenity& a, const Amenity& b)
{
return b.get_score() < a.get_score();
}
void fill(ListFlt& vec, const ListA& vecA, int selectCode)
{
vec.clear();
ListA::const_iterator it;
switch (selectCode)
{
case 1: for (it = vecA.begin(); it != vecA.end(); ++it)
vec.push_back(it->get_avg_Jan_temp());
break;
case 2: for (it = vecA.begin(); it != vecA.end(); ++it)
vec.push_back(it->get_avg_hrs_tot_Jan_sun());
break;
case 3: for (it = vecA.begin(); it != vecA.end(); ++it)
vec.push_back(it->get_avg_Jul_temp());
break;
case 4: for (it = vecA.begin(); it != vecA.end(); ++it)
vec.push_back(it->get_avg_Jul_humidity());
break;
case 5: for (it = vecA.begin(); it != vecA.end(); ++it)
vec.push_back(it->get_avg_landform_topo_code_1_21());
break;
case 6: for (it = vecA.begin(); it != vecA.end(); ++it)
vec.push_back(log(100 * it->get_percent_area_next_to_water()));
break;
/*
case 7: vec.push_back( it->get_score() );
break;
*/
}
}
// 1 //
float get_avg(const ListFlt& vecF)
{
if (vecF.size() < 1) return 0; // prevent divide by zero and ... //
//const double sum = accumulate( vecF.begin(), vecF.end(), 0.0 );
double init = 0.0;
const double sum = accumulate(vecF.begin(), vecF.end(), init,
[](double& init, float val)
{ return init += val; });
return (float)sum / vecF.size();
}
// 2 //
float get_sd(const ListFlt& vecF, const float avg)
{
if (vecF.size() < 2) return 0; // prevent divide by zero and ... //
float init = 0.0;
float sum_sqs = accumulate(vecF.begin(), vecF.end(), init,
[avg](float& init, float val)
{ return init += (val - avg)*(val - avg); });
return sqrt(sum_sqs / (vecF.size() - 1));
}
void PrintIt::operator () (const Amenity& am)
{
cout << am.get_county() << ' ' << am.get_state() << ' ';
switch (choice)
{
case 1: cout << am.get_avg_Jan_temp(); break;
case 2: cout << am.get_avg_hrs_tot_Jan_sun(); break;
case 3: cout << am.get_avg_Jan_temp(); break;
case 4: cout << am.get_avg_Jul_humidity(); break;
case 5: cout << am.get_avg_landform_topo_code_1_21(); break;
case 6: cout << am.get_percent_area_next_to_water(); break;
case 7: cout << am.get_score(); break;
}
cout << '\n';
}
void set_scores(ListA& vecA)
{
float avgs[6] = { 0 }, sds[6] = { 0 };
ListFlt vecF;
for (int i = 0; i < 6; ++i)
{
fill(vecF, vecA, i + 1);
avgs[i] = get_avg(vecF);
sds[i] = get_sd(vecF, avgs[i]);
}
for (size_t i = 0; i < vecA.size(); ++i)
{
float sc = 0;
sc += (vecA[i].get_avg_Jan_temp() - avgs[0]) / sds[0];
sc += (vecA[i].get_avg_hrs_tot_Jan_sun() - avgs[1]) / sds[1];
sc += (vecA[i].get_avg_Jul_temp() - avgs[2]) / sds[2];
sc += (vecA[i].get_avg_Jul_humidity() - avgs[3]) / sds[3];
sc += (vecA[i].get_avg_landform_topo_code_1_21() - avgs[4]) / sds[4];
sc += (log(100 * vecA[i].get_percent_area_next_to_water()) - avgs[5]) / sds[5];
vecA[i].set_score(sc);
}
}
void print_top_bottom_n(ListA& vecA, int choice, int n)
{
cout << '\n' << Amenity::HEADERS[choice] << '\n';
cout << string(Amenity::HEADERS[choice].size(), '=') << '\n';
switch (choice)
{
case 1: sort(vecA.begin(), vecA.end(), cmpJanTemp); break;
case 2: sort(vecA.begin(), vecA.end(), cmpJanSunHrs); break;
case 3: sort(vecA.begin(), vecA.end(), cmpJulTemp); break;
case 4: sort(vecA.begin(), vecA.end(), cmpJulHumidity); break;
case 5: sort(vecA.begin(), vecA.end(), cmpTopoCode); break;
case 6: sort(vecA.begin(), vecA.end(), cmpPartNearWater); break;
case 7: sort(vecA.begin(), vecA.end(), cmpScore); break;
}
int count = 0,
size = vecA.size();
PrintIt prt(choice); // call ctor ... //
for (const auto &am : vecA)
{
++count;
if (count <= n)
{
prt(am);
if (count == n)
{
cout << "...\n";
}
}
else if (count > size - n)
prt(am);
}
}
Amenity.h
#ifndef AMENITY_H
#define AMENITY_H
#include <iostream>
#include <string>
#include <sstream> // re. stringstream
#include <vector>
#include <algorithm> // re. vector sort //
#include <numeric> // re. accumulate //
#include <cmath> // re. sqrt //
using std::vector;
using std::string;
using std::istream;
using std::ostream;
class Amenity
{
public:
Amenity(); // default ctor //
string get_state() const;
string get_county() const;
float get_avg_Jan_temp() const;
float get_avg_hrs_tot_Jan_sun() const;
float get_avg_Jul_temp() const;
float get_avg_Jul_humidity() const;
int get_avg_landform_topo_code_1_21() const;
float get_percent_area_next_to_water() const;
float get_score() const;
void set_score(float sc) { score = sc; }
static const string HEADERS[];
private:
int id;
string state; // 2 chars's //
string county;
float avg_Jan_temp;
float avg_hrs_tot_Jan_sun;
float avg_Jul_temp;
float avg_Jul_humidity;
int avg_landform_topo_code_1_21;
float percent_area_next_to_water;
float score;
// prototype for overload operator >> for Amenity objects ...
friend istream& operator >> (istream& is, Amenity& am);
// prototype for overload operator << for Amenity objects ...
friend ostream& operator << (ostream& os, const Amenity& am);
};
typedef vector< Amenity > ListA;
typedef vector< float > ListFlt;
bool cmpJanTemp(const Amenity& a, const Amenity& b);
bool cmpJanSunHrs(const Amenity& a, const Amenity& b);
bool cmpJulTemp(const Amenity& a, const Amenity& b);
bool cmpJulHumidity(const Amenity& a, const Amenity& b);
bool cmpTopoCode(const Amenity& a, const Amenity& b);
bool cmpPartNearWater(const Amenity& a, const Amenity& b);
bool cmpScore(const Amenity& a, const Amenity& b);
class PrintIt
{
public:
PrintIt(int choice = 1) : choice(choice) {}
void set_choice(int ch) { choice = ch; }
void operator () (const Amenity& am);
private:
int choice;
};
void fill(ListFlt& vec, const ListA& vecA, int selectCode = 1);
// 1 //
float get_avg(const ListFlt& vecF);
// 2 //
float get_sd(const ListFlt& vecF, const float avg);
void set_scores(ListA& vecA);
void print_top_bottom_n(ListA& vecA, int choice, int n);
#endif //* AMENITY_H *//
Makefile
#Assign compiler variables
CC=g++
CCXFLAGS=-std=c++11
#Create object code to executable
myprog: amenity.o assign4.o
$(CC) $(CFLAGS) -o amenity.o assign4.o
#Create source code to object code
amenity.o: amenity.cc Amenity.h
$(CC) $(CLFAGS) -c amenity.cc
assign4.o: assign4.cc Amenity.h
$(CC) $(CFLAGS) -c assign4.cc
clean:
-rm *.o myprog
If anyone can help me fix these error and fix my makefile to compile, I would really appreciate it.
Thanks
If you have CXXFLAGS in your Makefile add -std=c++11 to it. If not, just put the following at the top of your Makefile:
CXXFLAGS=-std=c++11
Related
I'm trying to extract different datatype data from an ASCII array using templates where each datatype data is separated by a delimiter(':' in this case) also each datatype data can be preceded and succeeded by whitespaces which needs to removed. But I'm getting template instantiation error. Can somebody enlighten me how to accomplish this task. This is my sample code:
#include<iostream>
#include<string>
#include<cstring>
class Extract {
public:
inline Extract() {
length = 0;
std::memset(recvBuff, '\0', sizeof(recvBuff));
}
inline ~Extract() {
}
int length;
unsigned char recvBuff[1024];
template<typename T>
void extractData(short& start, short& end, T& val, char delimiter, short dataType) {
while(end <= length) {
if(recvBuff[end] == delimiter)
break;
end++;
}
if(end >= length)
return;
std::string token(recvBuff[start + 1], end - start - 1);
std::string trimmedToken;
std::string::size_type first = token.find_first_not_of(" \n\r\t\f\v");
std::string::size_type last = token.find_last_not_of(" \n\r\t\f\v");
if((first == std::string::npos) || (last == std::string::npos))
return;
else
trimmedToken.assign(token, first, (last - first + 1));
if(dataType == 1) { //char
if(trimmedToken.size() == 1)
val = trimmedToken.at(0);
}
else if(dataType == 2) { //int
if(trimmedToken.size() > 0)
val = std::stoi(trimmedToken);
}
else if(dataType == 3) { //float
if(trimmedToken.size() > 0)
val = std::stod(trimmedToken);
}
else if(dataType == 4) { //std::string
val.assign(trimmedToken);
}
}
};
int main(int argc, char* argv[]) {
//"contains mixed ascii data of char, int, float separated by :" for example
//" CMD : 123 : 3453.45646 : REP : T : 2424 : 3424 : 803424.2312 "
char buff[1024];
Extract objExtract;
objExtract.length = 60; // some dummy value for time being
std::memcpy(objExtract.recvBuff, buff, objExtract.length);
short start = 0;
short end = 1;
std::string data1;
objExtract.extractData(start, end, data1, ':', 4);
int data2;
objExtract.extractData(start, end, data2, ':', 2);
double data3;
objExtract.extractData(start, end, data3, ':', 3);
std::string data4;
objExtract.extractData(start, end, data4, ':', 4);
char data5;
objExtract.extractData(start, end, data5, ':', 1);
int data6;
objExtract.extractData(start, end, data6, ':', 2);
int data7;
objExtract.extractData(start, end, data7, ':', 2);
double data8;
objExtract.extractData(start, end, data8, ':', 3);
std::cout << data1 << "\t" << data2 << std::endl;
return 0;
}
When you call extractData for example for data2 the code
else if(dataType == 4) { //std::string
val.assign(trimmedToken);
}
is compiled. Type of val is int&. You got error because int doesn't have assign method.
With C++17 you can use if constexpr (condition) { block }, where condition is known at compile-time, if it is true, {block} will be compiled.
You can change signature of function to be:
template<typename T>
void extractData(short& start, short& end, T& val, char delimiter) {
and if block can be rewritten:
if constexpr (std::is_same_v<T,char>) { //char
if(trimmedToken.size() == 1)
val = trimmedToken.at(0);
}
else if constexpr(std::is_same_v<T,int>) { //int
if(trimmedToken.size() > 0)
val = std::stoi(trimmedToken);
}
else if constexpr (std::is_same_v<T,float>) { //float
if(trimmedToken.size() == 1)
val = std::stod(trimmedToken);
}
else if constexpr (std::is_same_v<T,std::string>) { //std::string
val.assign(trimmedToken);
}
you don't need to pass dataType, because it can be deduced from third parameter.
Under C++11 you can declare function template which does conversion, and you have to provide specialization for all types you want to support:
template<class T>
void convert(std::string, T&);
template<>
void convert<char>(std::string trimmedToken, char& val) {
if(trimmedToken.size() > 0)
val = std::stoi(trimmedToken);
}
template<>
void convert<int>(std::string trimmedToken, int& val) {
if(trimmedToken.size() > 0)
val = std::stoi(trimmedToken);
}
template<>
void convert<float>(std::string trimmedToken, float& val) {
if(trimmedToken.size() == 1)
val = std::stod(trimmedToken);
}
template<>
void convert<std::string>(std::string trimmedToken, std::string& val) {
val.assign(trimmedToken);
}
then remove if block and replace it by one line:
convert(trimmedToken,val);
when you call convert with val which is not supported by specializations, you will get linker's error. So you need to add version for double.
I am trying to achieve the same as RapidCheck: call any Callable no matter its arguments.
Here is an example from RapidCheck:
#include <rapidcheck.h>
int main() {
rc::check("Addition is commutative.",
[](int a, int b) {
RC_ASSERT(a + b == b + a);
});
return 0;
}
Unlike RapidCheck, which uses random data to call the Callable, I
would like to use a source of data. In particular, I am casting a uint8_t array to whatever type I need. (See the example below.)
I am okay with using C++17 but would prefer C++11. I currently only have a C++17 example.
My example below works for an arbitrary number of arguments to a Callable but not for arbitrary types of argument. And certainly not for mixed types of arguments.
I am doing this, so that I can use the awesome API of RapidCheck with libFuzzer from LLVM. Similar to my previous approach here (Example).
What I have so far with some comments (online):
// Compiles with Clang(trunk)/GCC(7.2) using -std=c++17!
#include <cassert>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <type_traits>
/** Provides access to a uint8_t array as specific types.
*
* Fulfills thus the LLVMFuzzerTestOneInput-interface, which uses
* (uint8_t *Data, size_t Size) as input.
*/
class RawQueue {
public:
RawQueue(uint8_t *Data, size_t Size)
: data_(Data), size_(Size / sizeof(uint8_t)), index_(0){};
/** Takes one element of type T from queue.
*
* Throws if empty.
*
* NOTE: Little endianess means that uint8_t {1, 0, 0, 0} == int {1}.
*/
template <typename T> T pop() {
assert(data_);
std::scoped_lock<std::mutex> lock(data_mutex_);
const size_t new_index = index_ + sizeof(T) / sizeof(uint8_t);
if (new_index > size_) {
std::runtime_error(
"Queue depleted!"); // TODO: Thou shall not use plain runtime_error!
}
const T val = *reinterpret_cast<const T *>(&(data_[index_]));
index_ = new_index;
return val;
}
private:
const uint8_t *data_; ///< Warning: Ownership resides outside of RawQueue.
std::mutex data_mutex_;
const size_t size_;
size_t index_;
};
template <> std::string RawQueue::pop<std::string>() {
return std::string("Left-out for brevity.");
};
template <typename T, typename F, typename... Args>
decltype(auto) call(RawQueue *Data, F &&f, Args &&... args) {
if constexpr (std::is_invocable<F, Args...>::value) {
return std::invoke(f, args...);
} else {
assert(Data);
// Is there a way to deduce T automatically and for each argument
// independently?
auto val = Data->pop<T>();
return call<T>(Data, f, val, args...);
}
}
int adder(int a, int b, int c) { return a + b + c; }
std::string greeter(const std::string &name) { return "Hello, " + name + "!"; }
int mixed_arguments(int i, float f, const std::string &s) { return 42; }
int main() {
constexpr size_t Size = 16;
uint8_t Data[Size] = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0};
RawQueue data(Data, Size);
auto res_int = call<int>(&data, adder);
std::cout << "Integer result: " << res_int << std::endl;
auto res = call<std::string>(&data, greeter);
std::cout << "String result: " << res << std::endl;
// Impossible with current approach:
// std::cout << "Mixed-types: " << call(&data, mixed_arguments) << std::endl;
return 0;
}
You could use variadic templates.
If you want to call, at runtime, an arbitrary function of arbitrary signature with arbitrary arguments, you should consider using libffi (a foreign function interface library which knows your ABI and calling conventions).
I found a solution using callable.hpp. Answers which do not rely on an external library are still welcome!
The relevant new addition is this:
constexpr size_t pos = sizeof...(args);
typedef typename callable_traits<F>::template argument_type<pos> T;
auto val = Data->pop<T>();
Complete Example:
#include <cassert>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <type_traits>
#include "external/callable/callable.hpp"
class RawQueue {
public:
RawQueue(uint8_t *Data, size_t Size)
: data_(Data), size_(Size / sizeof(uint8_t)), index_(0){};
/** Takes one element of type T from queue.
*
* Throws if empty.
*
* NOTE: Little endianess means that uint8_t {1, 0, 0, 0} == int {1}.
*/
template <typename T> T pop() {
assert(data_);
std::scoped_lock<std::mutex> lock(data_mutex_);
const size_t new_index = index_ + sizeof(T) / sizeof(uint8_t);
if (new_index > size_) {
// TODO: Thou shall not use plain runtime_error!
std::runtime_error("Queue depleted!");
}
const T val = *reinterpret_cast<const T *>(&(data_[index_]));
index_ = new_index;
return val;
}
private:
const uint8_t *data_; ///< Warning: Ownership resides outside of RawQueue.
std::mutex data_mutex_;
const size_t size_;
size_t index_;
};
template <> std::string RawQueue::pop<std::string>() {
std::scoped_lock<std::mutex> lock(data_mutex_);
assert(data_);
assert(index_ < size_);
size_t string_length = data_[index_]; // Up-to 255 ought to be enough.
const size_t new_index =
index_ + string_length + 1; // +1 b/c first value is length of string.
if (new_index > size_) {
// TODO: Thou shall not use plain runtime_error!
std::runtime_error("Queue depleted!");
}
const std::string val(reinterpret_cast<const char *>(&(data_[index_ + 1])),
string_length);
index_ = new_index;
return val;
};
template <typename F, typename... Args>
decltype(auto) call(RawQueue *Data, F &&f, Args &&... args) {
if constexpr (std::is_invocable<F, Args...>::value) {
return std::invoke(f, args...);
} else {
assert(Data);
constexpr size_t n_already = sizeof...(args);
constexpr size_t n_needed = callable_traits<F>::argc;
static_assert(n_needed >= n_already, "Too many arguments!");
constexpr size_t pos = n_already;
typedef typename callable_traits<F>::template argument_type<pos> T;
auto val = Data->pop<T>();
return call(Data, f, args..., val);
}
}
int adder(int a, int b, int c) { return a + b + c; }
std::string greeter(std::string a) { return "hello " + a; };
void mixed(int i, float f, std::string s) {
std::cout << "Mixed: " << i << ", " << f << ", " << s << std::endl;
}
int main() {
constexpr size_t Size = 28;
// clang-format off
uint8_t Data[Size] = {
3, 'A', 'd', 'a',
1, 0, 0, 0,
2, 0, 0, 0,
4, 0, 0, 0,
42, 0, 0, 0,
0xDA, 0x0F, 0x49, 0x40, // 3.141...
3, 'P', 'i', '!'};
// clang-format on
RawQueue data(Data, Size);
std::cout << "String: " << call(&data, greeter) << std::endl;
std::cout << "Integers: " << call(&data, adder) << std::endl;
call(&data, mixed);
call(&data, []() { std::cout << "Nothing to do!" << std::endl; });
return 0;
}
Prints:
String: hello Ada
Integers: 7
Mixed: 42, 3.14159, Pi!
Nothing to do!
#ifndef HASHMAP_H
#define HASHMAP_H
#include <iostream>
#include <string>
#include <vector>
using namespace std;
enum Status{open , active, deactivated };
//template <typename T>
template</*typename Key,*/ typename T>
class hashmap{
private:
class Node{
public:
const string Key;
//vector<T> values;
T value;
Status status;
Node(string key, T val) :Key(key), value(val), status(active){}
void operator =(const Node &n){
string *ptr;
ptr = (string*)(&(this->Key));
*ptr = n.Key;
//Node(n);
this->status = n.status;
this->value = n.value;
}
Node() :status(open){}
Node(const string& key) :Key(key), status(active){}
//Node(const Node &n) : value(n.val), status(n.status){}
};
//typedef map<
unsigned int hash(const string& s, int tableSize){
unsigned int h = 0;
/*each(s)*/
for(auto it : s) h = 31 * h + unsigned(it);
return h % tableSize;
}
unsigned int hash(const string& s){
return hash(s, table_size);
}
int table_size = 103;
vector<Node> table;
typedef typename vector<Node>::iterator iter;
public:
//default constructor
hashmap(){
table = vector<Node>(table_size);
}
//copy constructor
hashmap(const hashmap& x){
table = x.table;
//for (auto it = )
}
//assignment operator //has been removed
hashmap& operator=(const hashmap& x){
this->table.erase(this->table.begin(), this->table.begin() + 103);
for ( int i = 0; i < x.table_size; i++){
this->table.push_back(x.table.at(i));
}
return *this;
}
//destructor
~hashmap(){
table.clear();
}
//index operator
T& operator[](const string x){
int h = hash(x, table.size());
if (table[h].Key == x){
return (table[h].value);
}
else {
Node* n = new Node(x);
table[h] = *n;
return (table[h].value);
}
}
//Node test
void okay(const string x,int i){
Node *temp = new Node(x, i);
cout << temp->status << endl;
/*cout << table[1].status << endl;
cout << table[2].status << endl;
table.at(0) = (*temp);
cout << table[0].Key << endl;
cout << table[0].value << endl;
cout << table[3].status << endl;*/
}
int stride(int x){
return (7-x%7);
}
//find()
iter find(const string& x){
int h = hash(x);
int s = stride(h);
int t = table_size;
int z;
//for (int i = 0; i < t; i++){
for (int i = hash(x, table_size) % t; i != t; i = (i + stride(h)) % t){
z = (h + i*s) % table_size;
if (table[z].status == open) return NULL;
if (table[z].status == deactivated) continue;
if (table[z].Key == x) return &table[h];
}
return table.end();
}
//begin()
iter begin(){
return table.begin();
}
//end()
iter end(){
return table.end();
}
};
#endif // !HASHMAP_H
Everything seems to be working fine except the find function. It's suppose to probe through the vector and return values upon conditions but the problem I'm having is I get these errors about return type conflicts.
Error2error C2664: 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap::Node>>>::_Vector_iterator(const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap::Node>>> &)' : cannot convert argument 1 from 'hashmap<int>::Node *' to 'const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>> &'
Error1error C2664: 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>>::_Vector_iterator(const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>> &)' : cannot convert argument 1 from 'int' to 'const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>> &'
How can I edit the iterator to fix this?
thank you.
The common "solution" to use GetProcAddress with C++ is "extern "C", but that breaks overloading. Name mangling allows multiple functions to co-exist, as long as their signature differs. But is there a way to find these mangled names for GetProcAddress?
The VC++ compiler knows its own name mangling scheme, so why not use that? Inside template<typename T> T GetProcAddress(HMODULE h, const char* name), the macro __FUNCDNAME__ contains the mangled name of GetProcAddress. That includes the T part. So, inside GetProcAddress<void(*)(int), we have a substring with the mangled name of void(*)(int). From that, we can trivially derive the mangled name of void foo(int);
This code relies on the VC++ macro __FUNCDNAME__. For MinGW you'd need to base this on __PRETTY_FUNCTION__ instead.
FARPROC GetProcAddress_CppImpl(HMODULE h, const char* name, std::string const& Signature)
{
// The signature of T appears twice in the signature of T GetProcAddress<T>(HMODULE, const char*)
size_t len = Signature.find("##YA");
std::string templateParam = Signature.substr(0, len);
std::string returnType = Signature.substr(len+4);
returnType.resize(templateParam.size()); // Strip off our own arguments (HMODULE and const char*)
assert(templateParam == returnType);
// templateParam and returnType are _pointers_ to functions (P6), so adjust to function type (Y)
std::string funName = "?" + std::string(name) + "##Y" + templateParam.substr(2);
return ::GetProcAddress(h, funName.c_str());
}
template <typename T>
T GetProcAddress(HMODULE h, const char* name)
{
// Get our own signature. We use `const char* name` to keep it simple.
std::string Signature = __FUNCDNAME__ + 18; // Ignore prefix "??$GetProcAddress#"
return reinterpret_cast<T>(GetProcAddress_CppImpl(h, name, Signature));
}
// Showing the result
struct Dummy { };
__declspec(dllexport) void foo( const char* s)
{
std::cout << s;
}
__declspec(dllexport) void foo( int i, Dummy )
{
std::cout << "Overloaded foo(), got " << i << std::endl;
}
__declspec(dllexport) void foo( std::string const& s )
{
std::cout << "Overloaded foo(), got " << s << std::endl;
}
__declspec(dllexport) int foo( std::map<std::string, double> volatile& )
{
std::cout << "Overloaded foo(), complex type\n";
return 42;
}
int main()
{
HMODULE h = GetModuleHandleW(0);
foo("Hello, ");
auto pFoo1 = GetProcAddress<void (*)( const char*)>(h, "foo");
// This templated version of GetProcAddress is typesafe: You can't pass
// a float to pFoo1. That is a compile-time error.
pFoo1(" world\n");
auto pFoo2 = GetProcAddress<void (*)( int, Dummy )>(h, "foo");
pFoo2(42, Dummy()); // Again, typesafe.
auto pFoo3 = GetProcAddress<void (*)( std::string const& )>(h, "foo");
pFoo3("std::string overload\n");
auto pFoo4 = GetProcAddress<int (*)( std::map<std::string, double> volatile& )>(h, "foo");
// pFoo4 != NULL, this overload exists.
auto pFoo5 = GetProcAddress<void (*)( float )>(h, "foo");
// pFoo5==NULL - no such overload.
}
Use dumpbin /exports 'file.dll' to get the decorated / undecorated name of all the symbols.
It's impossible to do it just by using GetProcAddress. However, one way to do it would be to enumerate all the exported functions for that particular module, and do a pattern matching to find all the mangled names.
More specifically, refer to this answer here. The only change you will need to make would be to pass in TRUE for MappedAsImage parameter and the return value of GetModuleHandle for Base parameter to ImageDirectoryEntryToData function call.
void EnumerateExportedFunctions(HMODULE hModule, vector<string>& slListOfDllFunctions)
{
DWORD *dNameRVAs(0);
_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory;
unsigned long cDirSize;
_LOADED_IMAGE LoadedImage;
string sName;
slListOfDllFunctions.clear();
ImageExportDirectory = (_IMAGE_EXPORT_DIRECTORY*)
ImageDirectoryEntryToData(hModule,
TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &cDirSize);
if (ImageExportDirectory != NULL)
{
dNameRVAs = (DWORD *)ImageRvaToVa(LoadedImage.FileHeader,
LoadedImage.MappedAddress,
ImageExportDirectory->AddressOfNames, NULL);
for(size_t i = 0; i < ImageExportDirectory->NumberOfNames; i++)
{
sName = (char *)ImageRvaToVa(LoadedImage.FileHeader,
LoadedImage.MappedAddress,
dNameRVAs[i], NULL);
slListOfDllFunctions.push_back(sName);
}
}
}
I can't quite fathom why you'd ever want/need a constexpr version of MSalters' solution, but here it is, complete with namespace mangling. Use as
using F = int(double*);
constexpr auto f = mangled::name<F>([]{ return "foo::bar::frobnicate"; });
constexpr const char* cstr = f.data();
where F is the function signature and foo::bar::frobnicate is the (possibly qualified) name of the function.
#include<string_view>
#include<array>
namespace mangled
{
namespace detail
{
template<typename F>
inline constexpr std::string_view suffix()
{
auto str = std::string_view(__FUNCDNAME__);
return str.substr(14, str.size() - 87);
}
template<typename L>
struct constexpr_string
{
constexpr constexpr_string(L) {}
static constexpr std::string_view data = L{}();
};
template<typename Name>
inline constexpr int qualifiers()
{
int i = -2, count = -1;
while(i != std::string_view::npos)
{
i = Name::data.find("::", i + 2);
count++;
}
return count;
}
template<typename Name>
inline constexpr auto split()
{
std::array<std::string_view, qualifiers<Name>() + 1> arr = {};
int prev = -2;
for(int i = arr.size() - 1; i > 0; i--)
{
int cur = Name::data.find("::", prev + 2);
arr[i] = Name::data.substr(prev + 2, cur - prev - 2);
prev = cur;
}
arr[0] = Name::data.substr(prev + 2);
return arr;
}
template<typename F, typename Name>
struct name_builder
{
static constexpr auto suf = detail::suffix<F>();
static constexpr auto toks = split<Name>();
static constexpr auto len = Name::data.size() + suf.size() - toks.size() + 6;
static constexpr auto str = [] {
std::array<char, len> arr = {};
arr[0] = '?';
int i = 1;
for(int t = 0; t < toks.size(); t++)
{
if(t > 0)
arr[i++] = '#';
for(auto c : toks[t])
arr[i++] = c;
}
arr[i++] = '#';
arr[i++] = '#';
arr[i++] = 'Y';
for(auto c : suf)
arr[i++] = c;
return arr;
}();
};
}
template<typename F, typename LambdaString>
inline constexpr std::string_view name(LambdaString)
{
using Cs = detail::constexpr_string<LambdaString>;
using N = detail::name_builder<F, Cs>;
return {N::str.data(), N::len};
}
}
GodBolt
I'm trying to compile a code in Visual Studio, but I keep getting the following error:
Error 4 error C3867: 'MindSet::Form1::handleDataValueFunc': function call missing argument list; use '&MindSet::Form1::handleDataValueFunc' to create a pointer to member c:\documents and settings\licap\desktop\mindset\mindset\mindset\Form1.h 122 1 MindSet
This is my code
#pragma endregion
void handleDataValueFunc(unsigned char extendedCodeLevel, unsigned char code,
unsigned char valueLength, const unsigned char *value, void *customData)
{
FILE *arq1;
FILE *arq2;
FILE *arq3;
arq1 = fopen("raw.txt","a");
arq2 = fopen("atencao.txt","a");
arq3 = fopen("meditacao.txt","a");
if (extendedCodeLevel == 0 && code == RAW_WAVE_CODE)
{
short rawValue = ((value[0] << 8) & 0xff00) | (0x00ff & value[1]);
printf("%d\n", rawValue);
fprintf(arq1,"%d\n",rawValue);
}
if (extendedCodeLevel == 0 && code == ATTENTION_LEVEL_CODE)
{
short attentionValue = (value[0] & 0xFF);
printf("%d\n", attentionValue);
fprintf(arq2,"%d\n",attentionValue);
}
if (extendedCodeLevel == 0 && code == MEDITATION_LEVEL_CODE)
{
short meditationValue = (value[0] & 0xFF);
printf("%d\n", meditationValue);
fprintf(arq3,"%d\n",meditationValue);
}
fclose(arq1);
fclose(arq2);
fclose(arq3);
}
private: System::Void IniciarCaptura_Click(System::Object^ sender, System::EventArgs^ e) {
SerialPort* port = new SerialPortW32();
if (port->open())
{
/* Initialize ThinkGear stream parser */
ThinkGearStreamParser parser;
THINKGEAR_initParser(&parser, PARSER_TYPE_PACKETS, handleDataValueFunc, NULL);
unsigned char byteRead;
for (int i = 0; i < 100000; i++)
{
if (port->read(&byteRead, 1) == 1)
{
THINKGEAR_parseByte(&parser, byteRead);
fflush(stdout);
}
else
{
//cerr << "Erro na leitura da porta" << endl;
break;
}
}
port->close();
}
else
{
//cout << port->getErrorMessage() << endl;
}
delete port;
//return 0;
}
};
}
I've already tried to add a "&" before "handleDataValueFunc", but it only returns another error message. Can anybody help?
You will have to use gcroot See http://msdn.microsoft.com/en-us/library/481fa11f.aspx
struct nativeMindSetFormHandle
{
nativeMindSetFormHandle(MindSet::Form1 ^ h) : handle(h) {}
gcroot<MindSet::Form1 ^> handle;
};
static void handleDataValueFuncProxy(unsigned char extendedCodeLevel,
unsigned char code, unsigned char valueLength, const unsigned char *value,
void *customData)
{
static_cast<nativeMindSetFormHandle *>(customData)->handle->handleDataValueFunc(extendedCodeLevel, code, valueLength, value, NULL);
}
And update IniciarCaptura_Click to include:
nativeMindSetFromHandle * nativeHandle = new nativeMindSetFormHandle(this);
THINKGEAR_initParser(&parser, PARSER_TYPE_PACKETS, handleDataValueFuncProxy, nativeHandle);
And don't forget to delete nativeHandle when you are done.