如何创建一个多次使用值的宏,而不复制它?

时间:2015-07-07 15:17:53

标签: c++ c++11 macros undefined-behavior forwarding-reference

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

#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而不调用未定义的行为?

3 个答案:

答案 0 :(得分:6)

你不需要一个宏。

dataDict = {email: "johndoe@gmail.com", t:213213.213213}
apiFields = ['email', 'password', 'backup_email', 'firstname', 
             'lastname', 'dob', 'username', 'position', 'industry', 
             'institution', 'verificationcode', 'confirmcode', 
             'signuphost', 'responses', 't']

str = "d41d8cd98f00b204"
for ind in apiFields
  str = str + dataDict[ind] if ind in dataDict
console.log(str)

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

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

那就是它。

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

答案 1 :(得分:4)

auto&&创建转发引用,即它接受任何内容。它(总是)创建一个右值引用。所以这样做:

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

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

答案 2 :(得分:2)

你想要的是std::tie

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

如果需要,您甚至可以使用它来定义宏。请注意,这仅适用于2元组 - 如果您需要3元组或更多元素,则需要稍微改变一下。例如,如果您有一个3元组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;