Enr*_*lis 0 c++ generics getter non-member-functions perfect-forwarding
(读完这篇文章及其接受的答案后,这个问题突然出现在我的脑海中。)
假设一个Foo您无法修改的类,它有一个publicmember bar,但没有它的 getter 。
您可能想要编写一个函数来在传递 a 时获取该成员Foo,以便您可以在更高阶的函数中使用它,例如std::transform和 类似的函数。
换句话说,给定这样一个类
struct Foo {
int bar{};
~Foo() { bar = -1; } // on most compilers this helps "verifying" that the object is dead
};
Run Code Online (Sandbox Code Playgroud)
我想要一些getFoo与具有相同语义的类型,其中是 类型的任何对象,可以是纯右值、x值或左值。getBar(expr-of-type-Foo)expr-of-type-Foo.barexpr-of-type-FooFoo
你怎么写呢?
我最初想到的是:
constexpr auto getBar = overload(
[](auto& foo) -> decltype(auto) { return (foo.bar); },
[](auto const& foo) -> decltype(auto) { return (foo.bar); },
[](auto&& foo) -> auto { return foo.bar; }
);
Run Code Online (Sandbox Code Playgroud)
(-> auto这是多余的,但我认为它在这种情况下提供了信息。)
我的推理如下。
我需要它getBar对于不同的值类别有不同的行为,因此最好将其编写为重载集;为此,我正在使用boost::hana::overload.
但是我不确定我发现的解决方案是最小的(假设它足够了)。
例如,
auto&给定我在/ auto const&/上重载的重载之一auto&&,后者只会捕获右值,因此在其他两种情况下,我知道我想返回一个引用,所以我可以返回-> auto&and而-> auto const&不是decltype(auto)甚至从returned 表达式:
constexpr auto getBar = overload(
[](auto& foo) -> auto& { return foo.bar; },
[](auto const& foo) -> auto const& { return foo.bar; },
[](auto&& foo) -> auto { return foo.bar; }
);
Run Code Online (Sandbox Code Playgroud)
不过,在这一点上,我认为我不需要两个重载(auto&) -> auto&/ (auto const&) -> auto const&,因为当输入表达式时,前者会自然地解析为后者const,所以我认为我可以这样做:
constexpr auto getBar = overload(
[](auto& foo) -> auto& { return foo.bar; },
[](auto&& foo) -> auto { return foo.bar; }
);
Run Code Online (Sandbox Code Playgroud)
但目前我看不到进一步简化它的方法。
#include<assert.h>
#include<boost/hana/functional/overload.hpp>
struct Foo {
int bar{};
~Foo() {
bar = -1;
}
};
int main() {
{
constexpr auto getBar = overload(
[](auto&& foo) -> auto { return foo.bar; },
[](auto& foo) -> auto& { return foo.bar; }
);
{
Foo foo{3};
assert(&getBar(foo) == &foo.bar);
assert(getBar(foo) == 3);
foo.bar = 4;
assert(foo.bar == 4);
assert(getBar(foo) == 4);
getBar(foo) = 5;
assert(foo.bar == 5);
assert(getBar(foo) == 5);
}
{
Foo const foo{3};
assert(&getBar(foo) == &foo.bar);
assert(getBar(foo) == 3);
//foo.bar = 3; // Expectedly fails to compile.
//getBar(foo) = 3; // Expectedly fails to compile.
}
{
auto const& foobar = getBar(Foo{3});
assert(foobar == 3);
//foobar = 5; // Expectedly fails to compile.
}
{
//auto& foobar = getBar(Foo{3}); // Expectedly fails to compile.
//auto& foobar = Foo{3}.bar; // Expectedly fails to compile.
}
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,对于最少的工作:
const auto getBar = std::mem_fn(&Foo::bar);
Run Code Online (Sandbox Code Playgroud)
这个特定的用例似乎可以满足您的需求。在 C++20 中,它升级为constexpr,但这可能可用也可能不可用。与具有可重载成员函数的另一个问题不同,成员变量是明确的。所以我会回到上面。
| 归档时间: |
|
| 查看次数: |
90 次 |
| 最近记录: |