Template method inside a class - c++

I have a class called time which has day, month and year.
I have a problem with returning the right value in my method, where it, depending on what we enter as a string "s" it should return an int value from one of those 3 fields.
So, for example, if I want to get days in my date I should call the function d["day"].
My question is, Is there something wrong with my code here? And, what should I put instead of
int operator[] (string s)
{
if (s == "day" || s == "month" || s == "year")
{
return ? ? ? ;
}
}

From the explanation, if I understood correctly, you need the following. You need to return appropriate member (i.e. either day or month or year) according to the string match. (Assuming that you have mDay, mMonth, and mYear as int eger members in your Date class)
int operator[] (std::string const& s)
{
if (s == "day") return mDay;
if (s == "month") return mMonth;
if (s == "year") return mYear;
// default return
return -1;
}
or alternatively using a switch statement
// provide a enum for day-month-year
enum class DateType{ day, month, year};
int operator[] (DateType type)
{
switch (type)
{
case DateType::day: return mDay;
case DateType::month: return mMonth;
case DateType::year: return mYear;
default: return -1;
}
}

A dimple way is to define the date as an array of three elements instead of declaring three separate data members.
In this case the operator can look the following way as it is shown in the demonstrative program below.
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <stdexcept>
class MyDate
{
private:
unsigned int date[3] = { 26, 12, 2019 };
public:
unsigned int operator []( const std::string &s ) const
{
const char *date_names[] = { "day", "month", "year" };
auto it = std::find( std::begin( date_names ), std::end( date_names ), s );
if ( it == std::end( date_names ) )
{
throw std::out_of_range( "Invalid index." );
}
else
{
return date[std::distance( std::begin( date_names ), it )];
}
}
};
int main()
{
MyDate date;
std::cout << date["day"] << '.' << date["month"] << '.' << date["year"] << '\n';
return 0;
}
The program output is
26.12.2019
Otherwise you should use either if-else statements or a switch statement within the operator.

Related

Recursively reversing a string without parameters

I've been given a class smartReverse which contains one member data which is a string called str. I have to implement a member method (without any sort of helper function which takes no parameters and returns the reversed version of str.
This is my attempt so far but this does nothing but send the first character to the end of the string. And from this point I'm pretty clueless. I know how to do this using a helper function but am not allowed to use them here.
string smartReverse::rev_recursive() const
{
if (str.length() <= 1)
return str;
char first_char = str[0];
smartReverse* remainder = new smartReverse(str.substr(1));
remainder->rev_recursive();
return remainder->getString() + first_char;
}
With memleak removed, and using rev_recursive result, the fixed version might be:
std::string smartReverse::rev_recursive() const
{
if (str.length() <= 1) {
return str;
}
char first_char = str[0];
smartReverse remainder(str.substr(1));
return remainder.rev_recursive() + first_char;
}
There is no any need to allocate an object of the type std::string dynamically. It is just a bad idea.
I do not know how the class smartReverse looks but here is its simplified version that has only one member function rev_recursive that reverses the stored string.
#include <iostream>
#include <string>
class smartReverse
{
public:
smartReverse( const std::string &s ) : s( s ) {}
std::string rev_recursive()
{
if ( s.size() < 2 ) return s;
char first = s.front(), last = s.back();
s = s.substr( 1, s.size() - 2 );
return s = last + rev_recursive() + first;
}
private:
std::string s;
};
int main()
{
smartReverse obj( "Hello Brennen Green" );
std::cout << obj.rev_recursive() << '\n';
return 0;
}
The program output is
neerG nennerB olleH
If the function shall be a constant member function then its implementation can look the following way
#include <iostream>
#include <string>
class smartReverse
{
public:
smartReverse( const std::string &s ) : s( s ) {}
std::string getString() const
{
return s;
}
std::string rev_recursive() const
{
if ( s.size() < 2 ) return s;
char first = s.front(), last = s.back();
return last + smartReverse( s.substr( 1, s.size() - 2 ) ).rev_recursive() + first;
}
private:
std::string s;
};
int main()
{
smartReverse obj( "Hello Brennen Green" );
std::cout << obj.getString() << '\n';
std::cout << obj.rev_recursive() << '\n';
return 0;
}
The program output is
Hello Brennen Green
neerG nennerB olleH
Pay attention to that the used approach is more efficient than when only one character is removed from the beginning of the string and then appended to the end because in the used approach the number of recursions is less than or equal to s.size() / 2 of the original string.

How can I use an * wildcard in an if statement?

I'm creating a simple program that is going to visit a website of the users choosing so I'm using an if statement like:
If (url == "http://")
{
cout << ("Connecting to ") << url;
}
else
{
cout << ("Invalid URL");
}
And I'm wondering how I can filter out strings that doesn't start with "http://" or "https://", I'm just starting out so help would be appreciated.
A clear, but not particularly fast way, is to use (assuming url is a std::string)
if (url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://"){
/*I don't start with http:// or https:// */
}
Here I'm using substr to extract the start of a std::string then using the overloaded != operator.
Note that if url is shorter than 7 or 8 characters, the behaviour is still well-defined.
You could define static const char HTTP[] = "http://" and use sizeof(HTTP) - 1 &c. so you don't hardcode the lengths, but that might be going a step too far.
For more generality you could venture into the murky world of regular expressions. See std::regex.
A possible option would be to store the known starting protocols into a vector of strings then use that vector and its fuctions as well as the strings functions to do your tests and if your url is a string object comparison is easy.
#include <string>
#include <vector>
int main {
const std::vector<std::string> urlLookUps { "http://", "https://" };
std::string url( "https://www.home.com" );
unsigned int size1 = urlLookUps[0].size();
unsigned int size2 = urlLookUps[1].size();
if ( url.compare( 0, size1, urlLookUps[0] ) == 0 ||
url.compare( 0, size2, urlLookUps[1] ) == 0 ) {
std::cout << url << std::endl;
} else {
std::cout << "Invalid Address" << std::endl;
}
return 0;
}
EDIT
You can take this to the next step and turn it into a simple function
#include <string>
#include <vector>
void testUrls( const std::string& url, const std::vector<std::string>& urlLookUps ) {
std::vector<unsigned int> sizes;
for ( unsigned int idx = 0; idx < urlLookUps.size(); ++idx ) {
sizes.push_back( urlLookUps[idx].size() );
}
bool foundIt = false;
for ( unsigned int idx = 0; idx < urlLookUps.size(); ++idx ) {
if ( url.compare( 0, sizes[idx], urlLookUps[idx] ) == 0 ) {
foundIt = true;
break;
}
}
if ( foundIt ) {
std::cout << url << std::endl;
} else {
std::cout << "Invalid URL" << std::endl;
}
} // testUrls
int main() {
const std::vector<std::string> urlLookUps { "http://", "https://" };
std::string url1( "http://www.home.com" );
std::string url2( "https://www.home.com" );
std::string url3( "htt://www.home.com" );
testUrl( url1, urlLookUps );
testUrl( url2, urlLookUps );
testUrl( url3, urlLookUps );
return 0;
} // main
This way you can pass both the URL to the function as well as a container of url protocols that the user may want to populate themselves. This way the function will search through all the strings that are saved into the vector of strings.

convert truthTable result into Boolean statement

I am trying to convert back the result of the truth-table into a Boolean statement.
For those who are not familiar I am going to write it detail.
I have a vector of string in a format like below. All string members inside vector have an equal length. Members are only composed by - or 0 or 1.
for example vector v contain 3 member with the length of 5 for each member.
string vv[] = { "--1-0" , "-1-1-" , "01-1-" };
std::vector<string> v(begin(vv), end(vv));
Each character of string represents another vector "A" member along with a Boolean operation. For instance,
first one --1-0 is (A[2] && !A[4])
I would like to convert my above vector v into
(A[2] && !A[4]) || (A[1] && A[3] ) || (!A[0] && A[1] && A[3])
What I want to do is to have a function with vectors v and A as inputs and the return is above Boolean statement. I am sure you have noticed that 1 is true, 0 is Not true and - is don't care status.
EDIT: I do NOT intend to solve a truthTable or Kmap. I already have the result. My result in the format of "v" vector. I want to create a link between V and A using Boolean statement.
Any suggestion is appreciated.
I suppose the problem is that I don't speak English well but isn't clear to me what do you exactly want.
If you want a function that given a vector of std::string and a vector of bool return the bool value, according your indications, it's easy to do (hoping no errors made).
You use std::begin() so I suppose C++11 is good for you
#include <vector>
#include <iostream>
#include <stdexcept>
bool singleStatement (const std::vector<bool> & a,
const std::string & s)
{
auto ret = true;
if ( a.size() < s.size() )
throw std::runtime_error("invalid size");
for ( unsigned i = 0U ; i < s.size() ; ++i )
switch ( s[i] )
{
case '-': break;
case '1': ret &= a[i]; break;
case '0': ret &= !a[i]; break;
default: throw std::runtime_error("invalid char"); break;
}
return ret;
}
bool statements (const std::vector<bool> & a,
const std::vector<std::string> & v)
{
auto ret = false;
for ( const auto & s : v )
ret |= singleStatement(a, s);
return ret;
}
int main ()
{
std::vector<bool> a { true, false, false, true, false };
std::vector<std::string> v { "--1-0" , "-1-1-" , "01-1-" };
std::cout << "statement is " << statements(a, v) << std::endl;
return EXIT_SUCCESS;
}

Addition on user-defined types C++

I am writing my own class(called "Longer") such that it can hold a number without any upper bound unlike int. I am using std::string for this.
I am having problem on performing addition.
If i simply add two string, i can't get correct result.
I thought of converting string to int and then performing addition,
but long string can't be converted to int.
How can i define my own way of adding two strings so that i get the desired result? Here is the code:
Longer.h
#pragma once
#include <string>
class Longer
{
public:
Longer(std::string number);
Longer add(Longer num2);
void print();
private:
std::string number;
};
Longer.cpp
#include "Longer.h"
#include <iostream>
#include <string>
Longer::Longer(std::string num): number(num)
{
}
Longer Longer::add(Longer num2){
return Longer(number+num2.number);
}
void Longer::print(){
std::cout<<number<<"\n";
}
main.cpp
#include <iostream>
#include "Longer.h"
int main(){
Longer num1("123456789101112");
Longer num2("121110987654321");
Longer num3 = num1.add(num2);
num3.print();
}
I don't wonder addition doesn't work like you intended. std::string is not meant to be used as an arbitrary-long number container, that's why.
You must define your own way to "add" two strings, which should consist into iterating backwards both strings (from the end) and compare single characters, by interpreting them as numbers.
without any upper bound unlike int
Be careful with such things. There will always be some upper bound with any solution, at the very least when your machine's memory is exhausted. A robust application should always have some kind of error checking.
If i simply add two string, i can't get correct result.
Well, that's obvious, isn't it? String concatentation doesn't know anything about mathematical semantics.
I thought of converting string to int and then performing addition,
but long string can't be converted to int.
Exactly. Internally converting the string to a built-in type would defeat the whole purpose of the solution.
How can i define my own way of adding two strings so that i get the
desired result?
The goal is apparently to support numbers bigger than what the built-in types provide.
First of all, are you really sure that your application needs to work with such huge numbers? Even a standard int should usually be more than enough, not to mention long long (standard since C++11 but practically usable even before that).
Perhaps what you really need is to detect invalid user input like "10000000000000000000000000".
String streams provide this error detection for you. Here is a complete example for you to play with, including exemplary usage of std::numeric_limits:
#include <iostream>
#include <stdexcept>
#include <exception>
#include <limits>
int ReadInt()
{
int result;
std::cin >> result;
if (!std::cin)
{
throw std::runtime_error("Illegal number");
}
return result;
}
int main()
{
try
{
std::cout << "Enter number (max: " << std::numeric_limits<int>::max() << ") > ";
int input = ReadInt();
std::cout << "You entered the following number: " << input << "\n";
}
catch (std::exception const &exc)
{
std::cerr << exc.what() << "\n";
}
}
Here are three example runs on my machine. The first with a "normal" small number, the second just barely larger than the maximum possible, the third exactly the largest possible integer:
Enter number (max: 2147483647) > 1000
You entered the following number: 1000
Enter number (max: 2147483647) > 2147483648
Illegal number
Enter number (max: 2147483647) > 2147483647
You entered the following number: 2147483647
Now, if you really really must support large integer numbers internally, don't reinvent the wheel. Use Boost.Multiprecision:
http://www.boost.org/doc/libs/1_55_0/libs/multiprecision/doc/html/index.html
Since the documentation of that particular library may be a bit hard to swallow, here is an ultra-simple example to get you started:
#include <iostream>
#include <stdexcept>
#include <exception>
#include <boost/multiprecision/cpp_int.hpp>
int main()
{
try
{
boost::multiprecision::int128_t number("100000000000000000000000000000000");
number *= 2;
std::cout << number << "\n";
}
catch (std::exception const &exc)
{
std::cerr << exc.what() << "\n";
}
}
This actually prints 200000000000000000000000000000000.
#include <iostream>
using namespace std;
class Longer {
public:
Longer(std::string number): number(number) {}
void print() { cout << number << endl; }
Longer add(Longer num2) {
char over = '0'; string it;
for(int i = number.size() - 1,
j = num2.number.size() - 1;
i >= 0 || j >= 0; i--, j--) {
char one = i >= 0 ? number[i] : '0';
char two = j >= 0 ? num2.number[j] : '0';
char dig = one-'0' + two-'0' + over;
over = '0'; if(dig > '9') {
dig -= 10; over = '1'; }
it.insert(0, 1, dig);
}
if(over != '0') it.insert(0, 1, over);
return Longer(it);
}
private:
std::string number;
};
int main() {
Longer num1("123456789101112"); num1.print();
Longer num2("121110987654321"); num2.print();
Longer num3 = num1.add(num2); num3.print();
}
Output:
123456789101112
121110987654321
244567776755433
But if that was not homework, look at boost::multiprecision::cpp_int
Here is a ready to use solution
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <iterator>
class Longer
{
public:
Longer() : value( 1, '0' ) {}
Longer (std::string s )
: value( s.rbegin(), s.rend() )
{}
Longer( const char *s )
: value( std::reverse_iterator<const char *>( s + std::strlen( s ) ),
std::reverse_iterator<const char *>( s ) )
{}
const Longer add( const Longer &number ) const;
void print( std::ostream &os = std::cout ) const
{
os << std::string( value.rbegin(), value.rend() );
}
private:
std::string value;
};
const Longer Longer::add( const Longer &number ) const
{
std::pair<std::string::size_type, std::string::size_type> sizes =
std::minmax( this->value.size(), number.value.size() );
std::string result;
result.reserve( sizes.second + 1 );
int overflow = 0;
auto out = std::transform( this->value.begin(),
std::next( this->value.begin(), sizes.first ),
number.value.begin(),
std::back_inserter( result ),
[&] ( char c1, char c2 ) ->char
{
char c = ( c1 - '0' ) + ( c2 -'0' ) + overflow;
overflow = c / 10;
return c % 10 + '0';
} );
std::string::const_iterator first, last;
if ( this->value.size() < number.value.size() )
{
first = std::next( number.value.begin(), sizes.first );
last = number.value.end();
}
else
{
first = std::next( this->value.begin(), sizes.first );
last = this->value.end();
}
std::transform(first, last, out,
[&]( char c )
{
return ( c = c - '0' + overflow ),
( overflow = c / 10 ),
( c % 10 + '0' );
} );
if ( overflow ) result.push_back( overflow + '0' );
Longer n;
n.value = result;
return n;
}
int main()
{
Longer n1( "12345678912345678" );
n1.print();
std::cout << std::endl;
Longer n2( "1123" );
n2.print();
std::cout << std::endl;
Longer n3 = n2.add( "877" );
n3.print();
std::cout << std::endl;
Longer n4( "9999999999" );
n4.print();
std::cout << std::endl;
Longer n5 = n4.add( "1" );
n5.print();
std::cout << std::endl;
return 0;
}
The output is
12345678912345678
1123
2000
9999999999
10000000000
Take into account that it is more convinient to store the string in the reverse order inside the class.

C++ detecting if input is Int or String

I'm a C++ newbie who came from Java, so I need some guidance on some really basic issues I'm stumbling upon as I go.
I'm reading lines from a file, and each line consists of 6 strings/ints, which will be sent as parameters to a temporary variable.
Example:
Local1,Local2,ABC,200,300,asphalt
However, there are two subtypes of variable. One has a string as the last parameter (like 'asphalt' in the example above). The other one has an int instead. I have a method that reads each parameter and sends it to a variable, but how do I detect if the last bit of string is an integer or a string beforehand, so I know if I should send it to a Type1 variable or a Type2 one?
Many thanks!
Since you want to determine the type of the last column, then this ought to work:
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <sstream>
#include <cctype>
#include <algorithm>
enum Types {
NONE,
STRING,
INTEGER,
DOUBLE
};
struct Found {
std::string string_val;
int integer_val;
double double_val;
enum Types type;
};
//copied verbatim from:
//http://stackoverflow.com/a/2845275/866930
inline bool isInteger(const std::string &s) {
if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p ;
std::strtol(s.c_str(), &p, 10);
return (*p == 0);
}
//modified slightly for decimals:
inline bool isDouble(const std::string &s) {
if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false ;
char * p ;
std::strtod(s.c_str(), &p) ;
return (*p == 0);
}
bool isNotAlpha(char c) {
return !(std::isalpha(c));
}
//note: this searches for strings containing only characters from the alphabet
//however, you can modify that behavior yourself.
bool isString (const std::string &s) {
std::string::const_iterator it = std::find_if(s.begin(), s.end(), isNotAlpha);
return (it == s.end()) ? true : false;
}
void determine_last_column (const std::string& str, Found& found) {
//reset found:
found.integer_val = 0;
found.double_val = 0;
found.string_val = "";
found.type = NONE;
std::string temp;
std::istringstream iss(str);
int column = 0;
char *p;
while(std::getline(iss, temp, ',')) {
if (column == 5) {
//now check to see if the column is an integer or not:
if (isInteger(temp)) {
found.integer_val = static_cast<int>(std::strtol(temp.c_str(), &p, 10));
found.type = INTEGER;
}
else if (isDouble(temp)) {
found.double_val = static_cast<double>(std::strtod(temp.c_str(), &p));
found.type = DOUBLE;
}
else if (isString(temp)) {
found.string_val = temp;
found.type = STRING;
}
}
++column;
}
if (found.type == INTEGER) {
std::cout << "An integer was found: " << found.integer_val << std::endl;
}
else if(found.type == DOUBLE) {
std::cout << "A double was found: " << found.double_val << std::endl;
}
else if(found.type == STRING) {
std::cout << "A string was found: " << found.string_val << std::endl;
}
else {
std::cout << "A valid type was not found! Something went wrong..." << std::endl;
}
}
int main() {
std::string line_t1 = "Local1,Local2,ABC,200,300,asphalt";
std::string line_t2 = "Local1,Local2,ABC,200,300,-7000.3";
Found found;
determine_last_column(line_t1, found);
determine_last_column(line_t2, found);
return 0;
}
This outputs and correctly assigns the appropriate value:
A string was found: asphalt
An integer was found: -7000.3
This version works on int, double, string; does not require boost; and, is plain vanilla C++98.
REFERENCES:
UPDATE:
This version now supports both positive and negative numbers that are integers or doubles, in addition to strings.
First, create an array that can store both strings and integers:
std::vector<boost::variant<std::string, int>> items;
Second, split the input string on commas:
std::vector<std::string> strings;
boost::split(strings, input, boost::is_any_of(","));
Last, parse each token and insert it into the array:
for (auto&& string : strings) {
try {
items.push_back(boost::lexical_cast<int>(string));
} catch(boost::bad_lexical_cast const&) {
items.push_back(std::move(string));
}
}