在std::tuple中,括号和花括号之间有什么不同

  • 本文关键字:之间 std tuple c++
  • 更新时间 :
  • 英文 :


今天我在使用std::tuple()std::tuple{}时遇到了一个werid行为。

这里有一个简单的演示:

#include <iostream>
#include <tuple>
#define   rd   ({ int       x = (std::cin >> x, x); x; })
template <typename... Args>
void log(const Args &...args) { ((::std::cout << args << ", "), ...); }
auto main() -> int {
auto [a, b] = std::tuple(rd, rd);
auto [c, d] = std::tuple{rd, rd};
log(a, b, c, d);
return {};
}

运行:

echo '1 2 3 4' > input
clang++ -std=c++17 demon.cpp
./a.out < input
g++ -std=c++17 demon.cpp
./a.out < input
cat demon.cpp

得到两个不同的结果:1, 2, 3, 42, 1, 3, 4。这出乎我的意料。我转向我的朋友,得到了";宏CCD_ 5是一个不特定的行为";。然而,在了解了一些关于非特定行为的知识后,我仍然对这个答案感到困惑。

你的朋友是对的。

发生未指定的行为是因为未指定函数参数的求值顺序,它可以以任何顺序发生,并且可以在调用之间更改。意味着std::cin的顺序不能得到保证。编译器可以自由地对它们进行重新排序。这适用于std::tuple(),因此输出不正确。

另一方面,对于支持的init列表,顺序是从左到右固定的,因此std::tuple{}是安全的,并且输出是有保证的。

此外,在rd中,在表达式中包含braked语句不是标准的C++,因此您可以由编译器决定。我非常推荐无宏重构,在表达式中隐藏std::cin似乎是在找麻烦。

为什么不简单的read_int()函数或通用的read_T?然后通过显式排序可以推广到read_Ts<T1,T2,T3...>。例如:

template<typename T>
T read_T(){
T x;
std::cin>> x;
return x;
}
template<typename...T>
auto read_Ts(){
return std::tuple{read_T<T>()...};
}

最新更新