In the following code fragment (I'm experimenting with it to understand how modern C++ is different):
auto input(auto p) {
std::cout << p << ' ';
long long i;
return
std::cin >> i
&& std::set<int>{EOF, '\n'}.contains(std::cin.get())
&& i >= 0
? std::optional{i}
: std::nullopt;
}
const auto input2() {
auto a = input("Enter the first operand:");
if (a) {
auto b = input("Enter the second operand:");
if (b) return std::optional{std::pair{a.value(), b.value()}};
}
return decltype(input2()){};
}
void reqNat() {
std::cout << "Operands must be natural numbers!";
}
void binary(auto f, char op) {
auto xy = input2();
if (xy) {
auto &[x, y] = xy.value();
std::cout << std::format("{} {} {} = {}", x, op, y, f(x, y));
}
else reqNat();
}
are x and y subobjects of xy? If so, is the const in the return type of input2 required to ensure it? What does the const change? Would it be good to put it on input too?
Yes, in:
...
xy.value()returns an lvalue reference to the object inside, and the reference on the left hand side binds to it.xandyare then going to be lvalues which name subobjects inside ofxy.No, and
consthas nothing to do with this. In:... the
constis harmful, because we are declaring an object withauto, notconst auto. This means we are unnecessarily calling the copy constructor ofstd::optional<std::pair<...>>to turn the returnedconstobject into a non-constobject.In general, it is not recommended to put
conston return types, because:It only makes us call the copy constructor unnecessarily. The following use of structured bindings works regardless of whether
input2()returns aconstor non-consttype.We should not put on
input, we should removeconstfrominput2.Stylistic Issues
Note that there are quite a few things in your code that aren't "good modern C++":