Initialize a variable with an expression

Hi, Is it impossible to initialize a variable with an expression such as

1
2
double perimeter { width + length };
double length { 2 * (width + length) };


for then use both variable after the user input to calculate the perimeter and the surface of the field such as

1
2
perimeter;
surface;


I ask because It doesn't work so I want to know why?
I've been looking for an explanation and what makes sense to me is how the function main() works in order of sequence or how works the initialization / assignment concept.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main()
{ 
	double width{};
	double length{};
	double perimeter{};
	double surface{};
	
	std::cout << "Enter the width of the field: ";
	std::cin >> width;
	std::cout << "Enter the length of the field: ";
	std::cin >> length;
	
	perimeter = width + length;       
        // perimeter;
 	surface = 2 * (width + length);  
        // surface;
	
	std::cout << "the perimeter is " << perimeter << '\n';
	std::cout << "the surface is " << surface << '\n';

	return 0;
}
Last edited on
The expressions are evaluated when the variables are initialized. What you could do is turn perimeter and surface into functions and pass the width and length as argument.

1
2
3
4
5
6
7
8
9
10
11
12
13
double perimeter(double width, double length)
{
	return width + length;
}

double surface(double width, double length)
{
	return 2 * (width + length);
}

...
std::cout << "the perimeter is " << perimeter(width, length) << '\n';
std::cout << "the surface is " << surface(width, length) << '\n';

Another way would be to create a field class with a constructor that takes the width and length as argument and have member functions for getting the width, length, perimeter and surface (without having to pass any arguments).
Last edited on
I understand both of your solution and will try them.

The expressions are evaluated when the variables are initialized


It couldn't work because it has to produce a single value after evaluation?

Another question, If I want to use uniform initialization, is my code efficient / acceptable enough?
Last edited on
It couldn't work because it has to produce a single value after evaluation?

Yes. A variable of type double can only store a value of type double. To store an expression would require something different.

You can kind of fake it with lambda expressions ...

1
2
3
4
5
auto perimeter = [&](){ return width + length; };
auto surface = [&](){ return 2 * (width + length); };

std::cout << "the perimeter is " << perimeter() << '\n';
std::cout << "the surface is " << surface() << '\n';

... but what happens here behind the scenes is that it creates class objects that contains references to the captured variables width and length and it overloads the function call operator so that you can "call" the object as if it were a function to calculate the value.

Without a lambda expression it would look something like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Perimeter
{
public:
	Perimeter(double& width, double& length)
	:	w(width),
		l(length)
	{
	}
	
	double operator()() const
	{
		return w + l;
	}
	
private:
	double& w;
	double& l;
};

Perimeter perimeter{width, length};

std::cout << "the perimeter is " << perimeter() << '\n'; // <-- same as before 

This might be an alternative if you only intend to use them inside a single function. Regular functions and classes are however easier to reuse across different functions.


Another question, If I want to use uniform initialization, is my code efficient / acceptable enough?

It looks fine except you should generally try to declare variables as late as possible, in the smallest scope possible. Preferably when you have a sensible value to initialize them with.

The declarations of width and length might be moved down a few lines (but it's not a big deal).

With perimeter and surface it's better to declare them when you calculate their values.

1
2
double perimeter = width + length;       
double surface = 2 * (width + length); 

Or if you prefer the "uniform initialization" syntax:

1
2
double perimeter { width + length };       
double surface { 2 * (width + length) }; 

Last edited on
C++ allows for variables to be instantiated just before first use, no need to do it the C way at the top of main.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

int main()
{
	std::cout << "Enter the width of the field: ";
	double width {};
	std::cin >> width;

	std::cout << "Enter the length of the field: ";
	double length {};
	std::cin >> length;

	double perimeter { width + length };
	double surface   { 2 * (width + length) };

	std::cout << "the perimeter is " << perimeter << '\n';
	std::cout << "the surface is " << surface << '\n';
}

You don't need to instantiate new variables to calculate the perimeter and surface, you can do the calculation within std::cout:
16
17
	std::cout << "the perimeter is " << width + length << '\n';
	std::cout << "the surface is " << 2 * (width + length) << '\n';

Ultimately the solution chosen is what works best for the overall program flow, maintainability and readability.
If the value of a variable isn't changed after it's initialised, then it can be marked as const.

 
const double perimeter { width + length };       


If the value of the variable is now tried to be changed elsewhere then the compiler will report an error.
I'm not sure what's supposed to be calculated here, but assuming a rectangle field then:

field perimeter is 2 * (width + length)
field surface area is width * length

???

To have 2 variables initialised from returned values, then:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <utility>

int main() {
	const auto calc {[](double w, double l) -> std::pair<double, double> { return {2 * (w + l), w * l}; }};

	double width {};

	std::cout << "Enter the width of the field: ";
	std::cin >> width;

	double length {};

	std::cout << "Enter the length of the field: ";
	std::cin >> length;

	const auto [per, area] {calc(width, length)};

	std::cout << "the perimeter is " << per << '\n';
	std::cout << "the surface area is " << area << '\n';
}

My code could have been a lot better by seeing your codes and reading your tips, guys. I need to rethink the way I approach problems. Its easy to get stuck on one way to solve a problem when you just have to take a step back and see the different options that you have and not restrict yourself to one way of doing it. As well as making it simple.

@ seeplus the width and length of the field after the user input and then display its perimeter and surface.
Last edited on
Topic archived. No new replies allowed.