5

我想创建一个宏,将一对解包成两个局部变量。如果它只是一个变量,我不想创建该对的副本,这将完成:

#define UNPACK_PAIR(V1, V2, PAIR) \
    auto& V1 = PAIR.first; \
    auto& V2 = PAIR.second;

UNPACK_PAIR(one, two, x);

但是,我也希望它不计算多次给出的表达式,例如这应该只调用expensive_computation()一次:

UNPACK_PAIR(one, two, expensive_computation());

如果我做:

#define UNPACK_PAIR_A(V1, V2, PAIR) \
    auto tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

然后它适用于expensive_computation()案例,但它会在案例中制作副本x。如果我做:

#define UNPACK_PAIR_R(V1, V2, PAIR) \
    auto& tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

然后它可以在x没有复制的情况下在案例中工作,但在expensive_computation()案例中失败。如果我做:

#define UNPACK_PAIR_CR(V1, V2, PAIR) \
    const auto& tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

#define UNPACK_PAIR_RR(V1, V2, PAIR) \
    auto&& tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

这些都可以编译和运行,但我怀疑它们会调用未定义的行为——我对此是否正确?另外,这些中的任何一个都有意义吗?

#define UNPACK_PAIR_RR(V1, V2, PAIR) \
    auto&& tmp = std::move(PAIR); \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

#define UNPACK_PAIR_RR(V1, V2, PAIR) \
    auto&& tmp = std::forward<decltype(PAIR)>(PAIR); \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

有没有办法创建一个适用于这两种用例的宏——x在给出表达式或函数调用的结果时,既不复制也不调用未定义的行为?

4

3 回答 3

6

您不需要为此使用宏。

auto p = std::make_pair(2, 3);
int x, y;
std::tie(x, y) = p;

如果您想引用一对现有成员:

auto p = std::make_pair(2, 3);
auto& x = p.first;
auto& y = p.second;

就是这样。

现在你可以继续做一些更具挑战性/有趣/重要的事情了。

于 2015-07-07T15:25:27.973 回答
4

auto&&创建一个转发引用,即它接受任何东西。它不会总是)创建右值引用。所以只需这样做:

#define UNPACK_PAIR(V1, V2, PAIR) \
    auto&& tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

但是,我强烈建议不要这样做(除非使用范围UNPACK_PAIR非常有限,并且该操作在该范围内确实无处不在)。它看起来默默无闻,对我没有真正的好处。想象一下,在 6 个月后回到项目,只需要两个小时就可以找到一个严重的错误。你会感谢自己使用非标准的基于宏的语法而不是可读的东西吗?

于 2015-07-07T15:29:33.653 回答
2

你想要的是std::tie.

decltype(p.first) x;
decltype(p.second) y;
std::tie(x,y) = p;

如果你愿意,你甚至可以用它来定义你的宏。请注意,这仅适用于 2 元组 - 如果您想要 3 元组或更多,您需要做一些不同的事情。例如,如果您有一个 3-tuple t

decltype(std::get<0>(t)) x;
decltype(std::get<1>(t)) y;
decltype(std::get<2>(t)) z;
std::tie(x,y,z) = t;
于 2015-07-07T15:35:32.930 回答