英文:
How to ensure elements of a returned array aren't copied?
问题
在以下代码片段中(我正在尝试理解现代C++的不同之处):
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();
}
x
和 y
是否是 xy
的子对象?如果是,input2
返回类型中的 const
是否是必需的?const
有什么改变?将其放在 input
上是否是一个好主意?
是的,x
和 y
是 xy
的子对象。在代码中的这一行:
auto &[x, y] = xy.value();
auto &[x, y]
使用结构化绑定(structured binding)将 xy.value()
中的值绑定到 x
和 y
上。这并不会改变 xy
的内容,但允许您更轻松地访问其中的值。
const
在 input2
返回类型中是可选的,它表示 input2
函数不会修改其返回的值。如果您不希望通过 xy
修改 x
和 y
的值,您可以在 input2
返回类型中使用 const
,这是一种良好的做法,以确保代码的可读性和安全性。
对于 input
,是否使用 const
取决于您的需求。如果您希望确保 input
函数不修改传递给它的参数,那么您可以在 input
函数的参数中使用 const
,这有助于表明这一点。但在代码示例中,input
函数并没有修改参数 p
,因此 const
并不是必需的。
英文:
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?
答案1
得分: 1
are
x
andy
subobjects ofxy
?
是的,在:
auto &[x, y] = xy.value();
... xy.value()
返回对象内的左值引用,左侧的引用与之绑定。x
和 y
随后将成为 xy
内的子对象的左值。
If so, is the
const
in the return type ofinput2
required to ensure it?
不需要,const
与此无关。在:
const auto input2() { /* ... */ }
... 这里的 const
是有害的,因为我们正在用 auto
声明一个对象,而不是 const auto
。这意味着我们不必要地调用了 std::optional<std::pair<...>>
的复制构造函数,将返回的 const
对象转换为非 const
对象。
一般来说,不建议在返回类型上放置 const
,因为:
- 对于基本类型,它会被忽略
- 对于类类型,它可能会强制进行不必要的复制
What does the
const
change? Would it be good to put it oninput
too?
它只会导致我们不必要地调用复制构造函数。
以下使用结构化绑定的方式不受 input2()
返回类型是 const
还是非 const
影响。
我们不应该在 input
上加上 const
,应该从 input2
中删除 const
。
风格问题
请注意,您的代码中有许多不符合 "好的现代 C++" 的地方:
// 构造一个 std::set 仅用于检查一个 int 是否为两个值中的一个过于冗余。
std::set<int>{EOF, '\n'}.contains(std::cin.get())
// 考虑使用更轻量级的方法,如 IILE
[c = std::cin.get()] { return c == EOF || c == '\n' }()
// 或者,至少将 set 设为 'static const'
// 过多使用推导返回类型。
// 函数名和参数没有告诉我们返回类型是 std::optional<long long>。
// 此外,不必要使用函数模板。
// 您可以只接受 std::string_view 参数。
auto input(auto p) { /* ... */ }
// 如果必须这样做,只需使用显式返回类型。
// 这一行非常令人惊讶,可以使用带有显式类型的 return std::nullopt;。
return decltype(input2()){};
英文:
> are x
and y
subobjects of xy
?
Yes, in:
auto &[x, y] = xy.value();
... xy.value()
returns an lvalue reference to the object inside, and the reference on the left hand side binds to it. x
and y
are then going to be lvalues which name subobjects inside of xy
.
> If so, is the const
in the return type of input2
required to ensure it?
No, and const
has nothing to do with this. In:
const auto input2() { /* ... */ }
// ...
auto xy = input2();
// note: this assertion would pass, because xy is not const
static_assert(!std::is_const_v<decltype(xy)>);
... the const
is harmful, because we are declaring an object with auto
, not const auto
. This means we are unnecessarily calling the copy constructor of std::optional<std::pair<...>>
to turn the returned const
object into a non-const
object.
In general, it is not recommended to put const
on return types, because:
- for fundamental types, it's ignored
- for class types, it may force unnecessary copying
> What does the const
change? Would it be good to put it on input
too?
It only makes us call the copy constructor unnecessarily.
The following use of structured bindings works regardless of whether input2()
returns a const
or non-const
type.
We should not put on input
, we should remove const
from input2
.
Stylistic Issues
Note that there are quite a few things in your code that aren't "good modern C++":
// Constructing a std::set just to check if an int is one of two values is excessive.
std::set<int>{EOF, '\n'}.contains(std::cin.get())
// Consider using something more lightweight, like an IILE
[c = std::cin.get()] { return c == EOF || c == '\n' }()
// alternatively, make the set 'static const' at least
// Excessive use of deduced return types.
// The function name and parameters don't tell us anything about the return
// type being std::optional<long long>.
// Also, unnecessary use of function templates.
// You could have just accepted a std::string_view parameter.
auto input(auto p) { /* ... */ }
// If you have to do this, just use an explicit return type.
// This line is very surprising and could have been return std::nullopt; with
// an explicit type.
return decltype(input2()){};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论