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;
}
Related
#include <iostream>
using namespace std;
int myNum1 = 0;
int myNum2 = 0;
int main() {
int smaller, bigger, a, b;
cout << " Enter two numbers :" << endl;
cin >> a, b;
smallerNumber(smaller, bigger, a, b);
cout << smaller << bigger << endl;
return 0;
}
int smallerNumber(int a, int b, int IsSmaller, int IsBigger){
if (a > b) {
a = IsBigger;
b = IsSmaller;
}
else if (a < b) {
a = IsSmaller;
b = IsBigger;
}
else if (a == b) {
a = IsSmaller;
b = IsBigger;
}
return a;
return b;
}
You need to decide if you want to modify the parameters of a function or return a single value.
Modifying the Parameters
Pass the return variables by reference:
void smallerNumber(int& a, int& b, int IsSmaller, int IsBigger)
{
if (a > b) {
a = IsBigger;
b = IsSmaller;
}
else if (a < b) {
a = IsSmaller;
b = IsBigger;
}
else if (a == b) {
a = IsSmaller;
b = IsBigger;
}
}
Pasing by reference allows your function to modify the parameters.
Returning Multiple Values
To return multiple values you'll need a data structure.
Here's an example using a struct.
struct BigSmall
{
int bigger;
int smaller;
};
BigSmall smallerNumber(int a, int b)
{
BigSmall result;
if (a > b) {
result.bigger = a;
result.smaller = b;
}
else if (a < b) {
result.bigger = b;
result.smaller = a;
}
else if (a == b) {
result.bigger = a;
result.smaller = a;
}
return result;
}
I am trying to init a static array in a function.
int query(int x, int y) {
static int res[100][100]; // need to be initialized to -1
if (res[x][y] == -1) {
res[x][y] = time_consuming_work(x, y);
}
return res[x][y];
}
How can I achieve this?
First of all, I strongly recommend moving from C arrays to std::array. If you do this you can have a function to perform the initialization (otherwise you can't, as a function cannot return C arrays):
constexpr std::array<std::array<int, 100>, 100> init_query_array()
{
std::array<std::array<int, 100>, 100> r{};
for (auto& line : r)
for (auto& e : line)
e = -1;
return r;
}
int query(int x, int y) {
static std::array<std::array<int, 100>, 100> res = init_query_array();
if (res[x][y] == -1) {
res[x][y] = time_consuming_work(x, y);
}
return res[x][y];
}
Another option, that I actually like more is to perform the init in a lambda:
int query(int x, int y) {
static auto res = [] {
std::array<std::array<int, 100>, 100> r;
for (auto& line : r)
for (auto& e : line)
e = -1;
return r;
}();
if (res[x][y] == -1) {
res[x][y] = time_consuming_work(x, y);
}
return res[x][y];
}
You can't do this. You need an explicit for loop and a flag to avoid initializing more than once:
int query(int x, int y) {
static bool initilized = false;
static int res[100][100]; // need to be initialized to -1
if (!initilized) {
initilized = true;
for (int i = 0; i != 100; ++i) {
for (int j = 0; j != 100; ++j) {
res[i][j] = -1;
}
}
}
if (res[x][y] == -1) {
res[x][y] = time_consuming_work(x, y);
}
return res[x][y];
}
You can do it for example the following way by means of introducing one more static variable
int query(int x, int y) {
static bool initialized;
static int res[100][100]; // need to be initialized to -1
if ( not initialized )
{
for ( auto &row : res )
{
for ( auto &item : row ) item = -1;
}
initialized = true;
}
if (res[x][y] == -1) {
res[x][y] = time_consuming_work(x, y);
}
return res[x][y];
}
You can use fill with std::array and a IIL(immediately invoked lambda) :
static std::array<std::array<int, 100>, 100> res = [] () {
std::array<int, 100> default_arr;
default_arr.fill(-1);
std::array<std::array<int, 100>, 100> ret;
ret.fill(default_arr);
return ret;
}();
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;
}
}
Yesterday my friend challenged me to write a function in C which would return an array of function pointers where i-th function would return i.
It is easy to get a similar effect in C++, but I am not sure how to do it in C.
Can anyone help me with that?
Edit.
The effect that I am looking for is something equivalent to this.
vector <function<int()>> get_functions(int n) {
vector <function<int()>> functions;
for (int i = 0; i < n; ++i) {
functions.emplace_back([i]() {
return i;
});
}
return functions;
}
int main() {
auto functions = get_functions(10);
for (auto f:functions) {
cout << f() << endl;
}
return 0;
}
Edit.
As asked in the comment section I provide my poor attempt on the challenge.
typedef int (*fun_t)(void);
int fun() { return 0; }
int fun1() { return 1; }
fun_t *get_functions() {
fun_t *functions = malloc(sizeof(fun_t) * 2);
functions[0] = fun;
functions[1] = fun1;
return functions;
}
int main() {
fun_t* funs=get_functions();
for (int i = 0; i < 2; ++i) {
printf("%d\n",funs[i]());
}
free(funs);
}
The C++ code is cheating. function<int()> is not a function pointer; in fact, it's not a pointer at all, it's a class.
Therefore the equivalent C code would look something like this:
#include <stdio.h>
#include <stdlib.h>
// function<int ()>, simplified version just for this task
typedef struct {
int (*code)(int);
int ctx;
} function_int_t;
// function<int()>::operator()()
int call(function_int_t fun) {
return fun.code(fun.ctx);
}
// lambda body
int proto(int ctx) {
return ctx;
}
function_int_t *get_functions(size_t n) {
function_int_t *functions = calloc(n, sizeof *functions);
if (!functions) {
abort(); // hey, that's how C++ does it
}
for (size_t i = 0; i < n; i++) {
functions[i] = (function_int_t){ proto, i }; // capture i
}
return functions;
}
int main(void) {
size_t n = 10;
function_int_t *functions = get_functions(n);
for (size_t i = 0; i < n; i++) {
printf("%d\n", call(functions[i]));
}
free(functions);
return 0;
}
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.