I have a code that uses a while statement. Inside
the conditional expression I do a lookup. At the same time the conditional expression checks the return value:
#include <map>
struct a {
a *up;
std::map<int,int> tbl;
};
void p(a *_a, int id) {
decltype(_a->tbl)::iterator i;
while (_a && (i = _a->tbl.find(id)) != _a->tbl.end()) {
i->second += 1;
_a = _a->up;
}
}
int main(int arc, char **argv) {
a _a1{0,{{0,10},{1,10}}};
a _a0{&_a1,{{2,11},{3,11}}};
p(&_a0, 0);
return 0;
}
However I would like to get rid of the explicit declaration of i. I would like to use auto. In pseudocode:
...
void p(a *_a, int id) {
while (_a && ((auto i = _a->tbl.find(id))) != _a->tbl.end()) {
i->second += 1;
_a = _a->up;
}
}
...
Is there a construct in c++11/14/17 that supports this kind of declarations inside an expression? Not only while(auto i = 1) {...} style declarations? Maybe there are some new features that allow this?
How about separating the two conditions? The main one for the loop to continue is _a, and the secondary one (which may always be true) is _a->tbl.find(id) != _a->tbl.end(). Return on its negation:
void p(a *_a, int id) {
while (_a) {
auto i = _a->tbl.find(id);
if (i == _a->tbl.end()) {
return;
}
i->second += 1;
_a = _a->up;
}
}
Related
My Code is below.
struct conv{
struct des
{
des(int a) {}
des(int a, int b) {}
des(int a, int b, int c) {}
};
};
int main(int argc, const char * argv[]) {
int a = 1;
int b = 1;
int c = 1;
if (a > 1)
{
auto conv_desc = conv::des(1, 2, 3);
} else if(b > 1) {
auto conv_desc = conv::des(1, 2);
} else {
auto conv_desc = conv::des(1);
}
return 0;
}
The code's pattern is extracted from mkldnn. The only thing I want to do is take auto conv_desc out of the if-else statement.
I tried to declare auto conv_desc out of the if-else statement.
It occurred an error:
Declaration of
variable 'conv_desc' with deduced type 'auto' requires an initializer
Or if I used the pointer like below, I got a null pointer.
Another way got an error:
Taking the address of a temporary object of type 'conv::des'
If I can't solve this problem, I will have to write a large piece of duplicate code in each branch.
Move your if code into separate function:
conv::des make_des(int a, int b) {
if (a > 1) {
return conv::des(1, 2, 3);
} else if(b > 1) {
return conv::des(1, 2);
} else {
return conv::des(1);
}
}
int main(int argc, const char * argv[]) {
int a = 1;
int b = 1;
int c = 1;
auto conv_desc = make_des(a, b);
return 0;
}
Don't use auto. If you need to declare a variable and can't assign a value yet, then auto can't be used.
int main(int argc, const char * argv[]) {
// ...
conv::des conv_desc; // calls default constructor.
if (a > 1)
{
conv_desc = conv::des(1, 2, 3);
} else if(b > 1) {
conv_desc = conv::des(1, 2);
} else {
conv_desc = conv::des(1);
}
// conv_desc is initialized at this point.
return 0;
}
You can't use a pointer like this
int *a;
{ // new scope
int b = 5;
a = &b; // error.
}
// b is no longer in scope here
When b goes out of scope, then a will be pointing at the address where b used to be, which is now no longer valid.
If you want to use a pointer then you can use new. However in that case you must release the memory afterwards.
int main(int argc, const char** argv)
{
conv::des *conv_desc = nullptr; // does not call default constructor.
if (a > 1)
{
conv_desc = new conv::des(1, 2, 3);
} else if(b > 1) {
conv_desc = new conv::des(1, 2);
} else {
conv_desc = new conv::des(1);
}
if (conv_desc == nullptr) { /* memory allocation failed */ }
// conv_desc is initialized at this point.
// ...
// remember to delete conv_desc
if (conv_desc != nullptr) { delete conv_desc; conv_desc = nullptr; }
return 0;
}
You also can use an immediately called lambda. This is a common pattern to make some variables const when they could not otherwise.
This solution is very similar to #yachoor answer but uses a lambda.
int main(int argc, const char * argv[]) {
int a = 1;
int b = 1;
int c = 1;
// Kind of an inline function that is called immediately
auto const conv_desc = [&]{
if (a > 1) {
return conv::des(1, 2, 3);
} else if(b > 1) {
return conv::des(1, 2);
} else {
return conv::des(1);
}
}();
// Parens calls the function
return 0;
}
Seems like you are making the code overly-complicated. It is not clear why you would want to differentiate between these three constructors in this way. Why not hide the complexity inside the object by using default values like this?
struct conv{
struct des
{
des(int a, int b = 0, int c = 0) {
if(a > 1) {
/// do some logic
} else if(b > 1) {
// do some logic
} else {
// do some logic
}
}
};
};
int main(int argc, const char * argv[]) {
int a = 1;
int b = 1;
int c = 1;
auto conv_desc = conv::des(a, b, c);
return 0;
}
If you move the if ... else chain into a separate function, you can use return
struct conv
{
struct des
{
des(int a) {
}
des(int a, int b) {
}
des(int a, int b, int c) {
}
};
};
conv::des make_conv_des(int a, int b)
{
if (a > 1) {
return conv::des(1, 2, 3);
} else if(b > 1) {
return conv::des(1, 2);
} else {
return conv::des(1);
}
}
int main(int argc, const char * argv[]) {
int a = 1;
int b = 1;
auto conv_des = make_conv_des(a, b);
return 0;
}
I'm working on a c++ project and I have a case as below:
void func(int a, int b)
{
if (some_bool)
{
generateString(generateFunc()); // different
}
for (auto it : myVector)
{
// do something
for (int i = 0; i < a + b; ++i)
{
if (some_bool2)
{
myData = generateInt();
}
else
{
myData2 = generateInt2(); // different
}
}
}
}
void func(int a, int b, string str)
{
if (some_bool)
{
generateString(generateFunc(str)); // different
}
for (auto it : myVector)
{
// do something
for (int i = 0; i < a + b; ++i)
{
if (some_bool2)
{
myData = generateInt();
}
else
{
myData2 = convertStrToInt(str); //different
}
}
}
}
As you see, I have two overloading functions.
Their logical structures are the same but some details are not.
I'm considering if there is some technique which can merge them so that I can have a better design. Because for now I have to change two times if I need to do some change.
You can use templates and do something like this:
template<typename F, typename... A>
void func(int a, int b, F &&f, A&&... a)
{
if (some_bool)
{
generateString(generateFunc(std::forward<A>(a)...)); // different
}
for (auto it : myVector)
{
// do something
for (int i = 0; i < a + b; ++i)
{
if (some_bool2)
{
myData = generateInt();
}
else
{
myData2 = std::forward<F>(f)(std::forward<A>(a)...); //different
}
}
}
}
Then call your function as it follows:
func(0, 0, generateInt2);
// or
func(0, 0, convertStrToInt, std::string{0});
I can't figure out the error in the following code
#include <iostream>
#include <vector>
using namespace std;
class Spell {
private:
string scrollName;
public:
Spell(): scrollName("") { }
Spell(string name): scrollName(name) { }
virtual ~Spell() { }
string revealScrollName() {
return scrollName;
}
};
class Fireball : public Spell {
private: int power;
public:
Fireball(int power): power(power) { }
void revealFirepower(){
cout << "Fireball: " << power << endl;
}
};
class SpellJournal {
public:
static string journal;
static string read() {
return journal;
}
};
string SpellJournal::journal = "";
void counterspell(Spell *spell) {
if((Fireball *firespell=dynamic_cast<Fireball*>(spell))!=NULL)
{
firespell->revealFirepower();
}
else
{
string scname=spell->revealScrollName();
int m = scname.size();
int n = SpellJournal::journal.size();
int L[m+1][n+1];
for(int i=0; i<=m; i++)
{
for(int j=0; j<=n; j++)
{
if(i==0 || j==0)
L[i][j] = 0;
else if(scname[i-1]==SpellJournal::journal[j-1])
L[i][j] = L[i-1][j-1]+1;
else
L[i][j] = max(L[i-1][j],L[i][j-1]);
}
}
cout<<L[m][n];
}
}
class Wizard {
public:
Spell *cast() {
Spell *spell;
string s; cin >> s;
int power; cin >> power;
if(s == "fire") {
spell = new Fireball(power);
}
else {
spell = new Spell(s);
cin >> SpellJournal::journal;
}
return spell;
}
};
int main() {
int T;
cin >> T;
Wizard Arawn;
while(T--) {
Spell *spell = Arawn.cast();
counterspell(spell);
}
return 0;
}
The error is that primary expression is expected before * in the statement
if((Fireball *firespell=dynamic_cast<Fireball*>(spell))!=NULL)
also
firespell' was not declared in this scope
I think 2nd error is related to first. I don't know what concept I am missing. I have been following this link http://en.cppreference.com/w/cpp/language/dynamic_cast
kindly help.
if((Fireball *firespell=dynamic_cast(spell))!=NULL)
replace by
if(Fireball *firespell = dynamic_cast<Fireball*>(spell))
or by
Fireball *firespell;
if( ( firespell = dynamic_cast(spell) ) != nullptr)
Also, I do not have idea how this segment was compiled.
int m = scname.size();
int n = SpellJournal::journal.size();
int L[m+1][n+1];
You can not declare array size in runtime, use dynamic allocation (malloc, new) or some high-level containers
EDIT: Readability decrease in 2-nd code block is controversial statement.
From if statement:
Condition [if ( condition ) statement_true] one of
one of expression which is contextually convertible to bool
declaration of a single non-array variable with a brace-or-equals initializer.
So, you can't have a declaration and a boolean convertible expression in a single if statement.
You have to define it before if:
Fireball* firespell = dynamic_cast<Fireball*>(spell);
if (firespell != nullptr)
//Do something
If it is a c++ program then you can just write
void counterspell(Spell *spell) {
if( Fireball *firespell=dynamic_cast<Fireball*>(spell) )
{
firespell->revealFirepower();
}
The original code is not compiled because a declaration is an operand of an expression in the if statement.
I'm trying to create a program that takes a polynomial function from the user, counts the number of terms it has, creates an array large enough to store all of the terms, and then stores the terms there. The problem is that I'm not quite sure how to add a private class variable (or more specifically, a string array) AFTER the program determines how the large the function is. I need this string array to be a private class variable because I want to be able to access its contents through other class methods to do things like, for example, cout each of the function terms.
main.cpp:
#include <iostream>
#include <string>
#include "Function.h"
using namespace std;
int main()
{
Function func1;
func1.coutFuncTerms();
func1.coutFunc();
return 0;
}
Function.h:
#ifndef FUNCTION_H
#define FUNCTION_H
#include <iostream>
#include <string>
#include "Function.h"
using namespace std;
class Function
{
public:
Function();
~Function();
void removePlus(string*);
void removeWhitespace(string*);
void setFuncTerms();
void splitTerms();
void coutFuncTerms();
void coutFunc();
void coutTerms(string);
protected:
private:
string func;
int funcTerms;
};
#endif
Function.cpp:
#include <iostream>
#include <string>
#include "Function.h"
using namespace std;
// Function Constructor
//
// Stores a function inputted by the user
// Adds a null character ('\0') to the end of a string
// Erases a redundant '+' sign at the beginning of a string if there's one there
// Erases any whitespace characters in a string
// Stores the number of terms in the function
Function::Function()
{
getline(cin, func);
setFuncTerms();
//splitTerms();
}
Function::~Function()
{
}
// removePlus Function
//
// Erases a redundant '+' sign at the beginning of a string if there's one there
void Function::removePlus(string* func)
{
if(func->at(0) == '+')
{
func->erase(0, 1);
}
}
// removeWhitespace Function
//
// Erases any whitespace characters in a string
void Function::removeWhitespace(string* func)
{
for(int x = 0; unsigned(x) < func->length() - 1; x++)
{
while(func->at(x) == ' ' || func->at(x) == '\t')
{
func->erase(x, 1);
}
}
}
// setFuncLength Function
//
// Finds the number of terms in a Function object's 'func' variable
// Assigns this number to the object's 'funcLength' variable
void Function::setFuncTerms()
{
funcTerms = 0;
for(int funcTerm = 0; unsigned(funcTerm) < func.length(); funcTerm += 1)
{
bool isAPotentialTerm = false;
bool isATrueTerm = false;
if(func.at(funcTerm) == '+' || func.at(funcTerm) == '-')
{
isAPotentialTerm = true;
}
if(isAPotentialTerm == true)
{
for(int newFuncTerm = funcTerm + 1; unsigned(newFuncTerm) < func.length(); newFuncTerm += 1)
{
if(func.at(newFuncTerm) == '+' || func.at(newFuncTerm) == '-')
{
break;
}
if(func.at(newFuncTerm) != ' ' && func.at(newFuncTerm) != '\t')
{
isATrueTerm = true;
break;
}
}
}
if(isATrueTerm)
{
funcTerms++;
}
}
}
// splitTerms Function
//
// Calls the splitTerm function for each term in 'func' according to the function array 'funcArray'
void Function::splitTerms()
{
string funcArray[funcTerms];
int tempFuncLength = 0;
for(int funcTerm = 0; unsigned(funcTerm) < func.length(); funcTerm += 1)
{
bool isAPotentialTerm = false;
bool isATrueTerm = false;
if(func.at(funcTerm) == '+' || func.at(funcTerm) == '-')
{
isAPotentialTerm = true;
}
if(isAPotentialTerm == true)
{
for(int newFuncTerm = funcTerm + 1; unsigned(newFuncTerm) < func.length(); newFuncTerm += 1)
{
if(func.at(newFuncTerm) == '+' || func.at(newFuncTerm) == '-')
{
break;
}
if(func.at(newFuncTerm) != ' ' && func.at(newFuncTerm) != '\t')
{
isATrueTerm = true;
break;
}
}
}
if(isATrueTerm)
{
string temp;
for(; unsigned(funcTerm) < func.length() && func.at(funcTerm) != '+' && func.at(funcTerm) != '-'; funcTerm += 1)
{
funcArray[tempFuncLength].append(1, func.at(funcTerm));
}
tempFuncLength++;
}
}
for(int x = 0; x < funcTerms; x++)
{
cout << "Term " << x + 1 << " is: " << funcArray[x] << endl;
}
}
void Function::coutFuncTerms()
{
cout << "Terms: " << funcTerms << endl;
}
void Function::coutFunc()
{
cout << "Function: " << func << endl;
}
void Function::coutTerms(string funcArrayTerm)
{
/*for(int x = 0; x < funcLength; x++)
{
cout << "Term " << x << " is: " << funcArray[x] << endl;
}*/
//cout << funcArray[0] << endl;
}
I highly recommend you change your design.
A function is a container of terms. So let's define a term:
A term minimally has a coefficient and an exponent:
struct Fundamental_Term
{
double coefficient;
int exponent;
};
If your function is only in terms of one variable, all you need is the Fundamental_Term. Otherwise, you need to have the base variable name:
struct Term_With_Base
: public Fundamental_Term
{
std::string variable_name;
};
Note: if you can't use inheritance, copy the member variables of Fundamental_Term into Term_With_Base.
Remember a function is a collection or container of terms. Assuming a function with multiple bases, we can declare:
struct Function
{
std::vector<Term_With_Base> terms;
};
Evaluation of Terms
To evaluate a function, f(x), all terms must be evaluated and their results summed.
This decomposes into two requirements: 1) Terms must have an evaluation method; 2) The function class must have an evaluation method that sums the terms.
So, we add an evaluation function to the base class:
struct Fundamental_Term
{
double coefficient;
int exponent;
double evaluate(double value)
{
return coefficient * pow(value, exponent);
}
};
struct Function
{
std::vector<Term_With_Base> terms;
double evauate(double value)
{
const unsigned int quantity = terms.size();
double result = 0.0;
for (unsigned int i = 0; i < quantity; ++i)
{
result = result + terms[i].evaluate(value);
}
return result;
}
};
When creating a function from a string, a preference is to create a constructor of Fundamental_Term that takes a string parameter. The term object should read its coefficient, variable name and exponent, not the Function container.
For more examples, search StackOverflow for "c++ parse term evaluation".
Edit 1: Inserting terms
One method to insert terms, is to have a method in the term data structure that loads a term from a string:
bool
Fundamental_Term ::
load_from string(const std::string& input,
unsigned int & start_position)
{
bool term_is_valid = false;
// Parse the string and load appropriate fields.
// Set the start position to the first position after the valid term.
// Set term_is_valid to true if the term has valid syntax.
return term_is_valid;
}
The Function object would have a member to load terms from a string.
bool
Function ::
load_terms_from_string(const std::string& input)
{
Term_With_Base term;
unsigned int position_in_string = 0;
bool term_is_valid = true;
while (term_is_valid && (position_in_string < input.size()))
{
term_is_valid = term.load_from_string(input, position_in_string);
if (term_is_valid)
{
terms.push_back(term);
}
}
}
The std::vector used to contain the terms will expand as necessary with each additional term that is parsed. The loop will terminate when the string is parsed or there is an invalid term.
This form does not compile with my VS2008 compiler. Should it be possible?
#include <iostream>
using namespace std;
int getvalue() { return 3; }
int main(int argc, char* argv[])
{
if((int val = getvalue()) == 3)
cout << "val=" << val << "\n";
return 0;
}
This form does work.
...
int val;
if((val = getvalue()) == 3)
...
Why does it not work?
It's not legal because you can't use a statement as an expression.
So, it's not the declaring a variable inside an if that's illegal, but the comparison.
Just like:
(int x = 3) == 3;
is illegal, whereas
int x = 3;
x == 3;
isn't.
If you don't want to litter in your scope, you can use а {} block:
...
{
int val;
if((val = getvalue()) == 3) {
...
}
}
...
val will be destroyed at the last } and won't be visible afterwards.