For our first project in my C++ course this semester we had to do a simple calculator program. My background is mostly in Functional languages. What's the best way to do generic programming/functional style in C++?
We're doing C++14 standard in this course, but C++17 also welcome!
main.cpp
#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <memory>
#include <cmath>
#include <stack>
#include <algorithm>
//function declarations
bool isdouble(std::string tok);
std::deque<std::string> readFile(char* argv[]);
//definitions
std::deque<std::string> readFile(char* argv[]){
// open the file for reading
std::ifstream in(argv[1]);
if (!in)
{
// Print an error and exit
std::cerr << "File could not be opened for reading!" << std::endl;
exit(1);
}
// vector to be read into
std::deque<std::string> tokens;
// read the file while we have input.
while (in) {
std::string buf;
in >> buf;
tokens.push_back(buf);
}
in.close();
return tokens;
}
template<typename T>
class wrap{
public:
T a;
T b;
std::string aString;
std::string bString;
wrap(T a,T b, std::string aString, std::string bString) :
a(a),b(b),aString(aString),bString(bString){}
};
wrap<double> doublePop(std::stack<std::string> &stack){
double a=std::stof(stack.top());
auto aString = (stack.top());
stack.pop();
double b=std::stof(stack.top());
auto bString = (stack.top());
stack.pop();
wrap<double> ret(a,b,aString,bString);
return ret;
}
wrap<int> intPop(std::stack<std::string> &stack){
int a=std::stoi(stack.top());
auto aString = (stack.top());
stack.pop();
int b=std::stoi(stack.top());
auto bString = (stack.top());
stack.pop();
wrap<int> ret(a,b,aString,bString);
return ret;
}
bool isdouble(std::string tok){
for(auto ch:tok){
if(ch == '.'){
return true;
}
}
return false;
}
bool doublesCheck(std::stack<std::string> &stack){
auto first = stack.top();
stack.pop();
auto second = stack.top();
stack.push(first);
return isdouble(first) || isdouble(second);
}
void calcsqrt(std::stack<std::string> &stack){
auto operand = stack.top();
stack.pop();
double c;
if(isdouble(operand)){
c = sqrt(std::stod(operand));
}else{
c = sqrt(std::stoi(operand));
}
auto checkDoubleVal = std::to_string(c);
if(isdouble(checkDoubleVal)){
std::cout << "sqrt "<< operand << " = " << c << std::endl;
stack.push(std::to_string(c));
}else{
int d = c;
std::cout << "sqrt "<< operand << " = " << d << std::endl;
stack.push(std::to_string(d));
}
}
void add(std::stack<std::string> &stack){
if(doublesCheck(stack)){
auto wrap = doublePop(stack);
auto c = std::to_string(wrap.a+wrap.b);
stack.push(c);
std::cout << wrap.aString << " + "<< wrap.bString << " = " << c << std::endl;
}else {
auto wrap = intPop(stack);
auto c = std::to_string(wrap.a+wrap.b);
stack.push(c);
std::cout << wrap.aString << " + "<< wrap.bString << " = " << c << std::endl;
}
}
void sub(std::stack<std::string> &stack){
if(doublesCheck(stack)){
auto wrap = doublePop(stack);
auto c = std::to_string(wrap.a-wrap.b);
stack.push(c);
std::cout << wrap.aString << " - "<< wrap.bString << " = " << c << std::endl;
}else {
auto wrap = intPop(stack);
auto c = std::to_string(wrap.a-wrap.b);
stack.push(c);
std::cout << wrap.aString << " - "<< wrap.bString << " = " << c << std::endl;
}
}
void mult(std::stack<std::string> &stack){
if(doublesCheck(stack)){
auto wrap = doublePop(stack);
auto c = std::to_string(wrap.a*wrap.b);
stack.push(c);
std::cout << wrap.aString << " * "<< wrap.bString << " = " << c << std::endl;
}else {
auto wrap = intPop(stack);
auto c = std::to_string(wrap.a*wrap.b);
stack.push(c);
std::cout << wrap.aString << " * "<< wrap.bString << " = " << c << std::endl;
}
}
void div(std::stack<std::string> &stack){
if(doublesCheck(stack)){
auto wrap = doublePop(stack);
auto c = std::to_string(wrap.a/wrap.b);
stack.push(c);
std::cout << wrap.aString << " / "<< wrap.bString << " = " << c << std::endl;
}else {
auto wrap = intPop(stack);
auto c = std::to_string(wrap.a/wrap.b);
stack.push(c);
std::cout << wrap.aString << " / "<< wrap.bString << " = " << c << std::endl;
}
}
void reverse(std::stack<std::string> &stack){
int times = std::stoi(stack.top());
stack.pop();
std::vector<std::string> buffer;
while(times > 0){
buffer.push_back(stack.top());
stack.pop();
times--;
}
for(auto item: buffer){
stack.push(item);
}
}
//main loop
int main(int argc, char* argv[]) {
std::stack<std::string> stack;
//read the file
auto tokens = readFile(argv);
//remove eof char
tokens.pop_back();
// setup the print out format for the precision required.
std::cout.setf(std::ios::fixed,std::ios::floatfield);
std::cout.precision(3);
bool done = false;
while(!done){
std::deque<std::string> buffer;
auto start = std::find(tokens.begin(),tokens.end(),"repeat");
auto end = std::find(tokens.begin(),tokens.end(),"endrepeat");
for(auto pos = start+1; pos != end; pos++){
buffer.push_back(*pos);
}
for(int i = 0; i < 3; i++){
tokens.insert(start,buffer.begin(),buffer.end());
}
start = std::find(tokens.begin(),tokens.end(),"repeat");
end = std::find(tokens.begin(),tokens.end(),"endrepeat");
tokens.erase(start,end+1);
//end process if all repeats processed
if(std::find(tokens.begin(),tokens.end(),"repeat") == tokens.end()){
done = true;
}
//process the tokens
for(std::string tok : tokens){
auto check = std::isdigit(static_cast<unsigned char>(tok[0]));
//if token is a number
if(check){
stack.push(tok);
}
else{
//empty check
if(stack.empty()){
std::cout << "not enough operands for this operation" << std::endl;
break;
}
if(tok == "add"){
add(stack);
continue;
}
if(tok == "sub"){
sub(stack);
continue;
}
if(tok == "mult"){
mult(stack);
continue;
}
if(tok == "div"){
div(stack);
continue;
}
if(tok == "pop"){
stack.pop();
continue;
}
if(tok == "sqrt"){
calcsqrt(stack);
continue;
}
if(tok == "reverse"){
reverse(stack);
continue;
}
if(tok == "repeat"){
continue;
}
if(tok == "endrepeat"){
continue;
}
std::cout << "invalid input, program exiting" << std::endl;
exit(1);
}
}
return 0;
}
}
somewhere... \$\endgroup\$