我想从一个函数中返回一些值,并将它们打包在元组中。因此,我有两种函数声明的可能性:
std::tuple<bool, string, int> f()
{
...
return std::make_tuple(false, "home", 0);
}
和
std::tuple<bool, string, int> f()
{
...
return std::forward_as_tuple(false, "home", 0);
}
这些函数是等价的吗? 你更喜欢哪一个函数?
std::forward_as_tuple()
创建一个由 引用 组成的元组。因为您无论如何都返回一个 tuple<bool, string, int>
,所以在这种情况下两者等效,但我认为第一种方法更清晰明了——当您没有转发任何内容时使用 forward_as_tuple()
是令人困惑的。
此外,正如Sebastian Redl在评论中提到的,make_tuple()
可以让编译器执行复制省略——根据C++11标准第12.8/31段,而 forward_tuple()
则不能(因为它返回的内容与函数的返回类型不同)。
I prefer,
std::tuple<bool, std::string, int> f()
{
...
return { false, "home", 0 };
}
上面的代码在clang/libc++ trunk下实际上可以编译通过。正如@AndyProwl在评论中所说,这不应该发生,因为std::tuple构造函数是显式的,并且通过初始化列表语法返回处于复制初始化上下文中,因此是复制列表初始化,当匹配到显式构造函数时失败。
我不知道clang/libc++之所以能够通过,我认为这可能是libc++中的一个bug。无论如何,不能对元组使用这种语法令人伤心...
我认为我意识到了这一点有多伤心(至少对我来说)。我开始习惯了这种语法,但人们被迫事先知道返回类型是否包含显式构造函数,才能使其工作。
这确实是libc++的扩展,更多信息请查看Howard Hinnant在这里的回答:https://dev59.com/dWUp5IYBdhLWcg3w5KvV#14963014。
这也是目前在libc++ bug列表中开放的:http://llvm.org/bugs/show_bug.cgi?id=15299。
这是相关提案:Daniel Krügler,Improving pair and tuple。
简而言之,这就是libc++中发生的情况:
#include <tuple>
#include <string>
struct S
{
explicit S(int) {}
};
int main()
{
std::tuple<int, std::string> t1 = { 1, "hello" }; // ok
std::tuple<std::string> t2 = "hello"; // ok
std::tuple<int, S> t3 = { 1, 1 }; // fail: an *element* is to be constructed explicitly
}
std::tuple
有一个显式构造函数,这意味着上面的代码将无法编译。 - Andy Prowl
std::make_tuple
。 - Xeoforward_as_tuple
用于在需要转发万能引用但作为元组时使用。如果您不知道这是什么意思,请不要使用它。 - Mooing Duck