以下代码使用clang(libc ++)编译,并使用gcc(libstdc ++)失败。为什么gcc(libstdc ++)抱怨初始化列表?我认为return参数使用统一初始化语法。
std::tuple<double,double> dummy() {
return {2.0, 3.0};
}
int main() {
std::tuple<double,double> a = dummy();
return 0;
}
错误:第22行:从初始化程序转换为'std :: tuple' list将使用显式构造函数'constexpr std :: tuple&lt; _T1,_T2&gt; :: tuple(_U1&amp; \ &amp;,_U2&amp;&amp;)[与_U1 = double; _U2 =双倍; =无效_T \ 1 =双倍; _T2 = double]'
注意: GCC(libstdc ++)(和clang(libc ++))接受
std::tuple<double,double> dummy {1.0, 2.0};
是不是一样的情况?
更新:这是一个libc ++扩展程序,请参阅http://llvm.org/bugs/show_bug.cgi?id=15299,并在下面由Howard Hinnant回答。
答案 0 :(得分:33)
与pair<>
不同,遗憾的是,tuple<>
的隐式构造是不可能的。您必须使用make_tuple()
:
#include <tuple>
std::tuple<double,double> dummy()
{
return std::make_tuple(2.0, 3.0); // OK
}
int main()
{
std::tuple<double,double> a = dummy();
return 0;
}
std::tuple
有一个可变参数构造函数,但标记为explicit
。因此,它不能用于这种情况,其中临时必须是可隐式构造的。根据C ++ 11标准的第20.4.2段:
namespace std {
template <class... Types>
class tuple {
public:
[...]
explicit tuple(const Types&...); // Marked as explicit!
template <class... UTypes>
explicit tuple(UTypes&&...); // Marked as explicit!
出于同样的原因,使用复制初始化语法来初始化元组是非法的:
std::tuple<double, double> a = {1.0, 2.0}; // ERROR!
std::tuple<double, double> a{1.0, 2.0}; // OK
或者在将它作为参数传递给函数时隐式构造元组:
void f(std::tuple<double, double> t) { ... }
...
f({1.0, 2.0}); // ERROR!
f(make_tuple(1.0, 2.0)); // OK
因此,如果在std::tuple
中返回dummy()
时明确构造#include <tuple>
std::tuple<double,double> dummy()
{
return std::tuple<double, double>{2.0, 3.0}; // OK
}
int main()
{
std::tuple<double,double> a = dummy();
return 0;
}
,则不会出现编译错误:
{{1}}
答案 1 :(得分:23)
Andy Prowl给出的答案是正确的。我想对libc ++实现发表评论,评论格式不允许我有足够的空间或格式选择。
DanielKrügler和我在一年前就这个问题进行了一次对话,他让我相信这个问题值得对libc ++进行扩展以获得实地经验。到目前为止,反馈都是积极的。不过我想澄清一点:这并不像从explicit
删除explicit constexpr tuple(UTypes&&...)
那么简单。
Daniel的计划是给tuple
一个完全尊重每个元素的隐式/显式构造的构造函数。并且 if 每个元素将从初始化列表中的每个参数隐式构造,然后元组构造是隐式的,否则它将是显式的。
例如:
假设:
#include <tuple>
struct A
{
};
struct B
{
B() = default;
B(A);
};
struct C
{
C() = default;
explicit C(A);
};
然后:
std::tuple<>
test0()
{
return {}; // ok
}
没有什么可说的。但这也没关系:
std::tuple<B>
test1B()
{
return {A()}; // ok B(A) implicit
}
因为从A
到B
的转换是隐含的。但是以下是编译时错误:
std::tuple<C>
test1C()
{
return {A()}; // error, C(A) is explicit
}
因为从A
到C
的转换是明确的。这种逻辑继续用于多元素元组。要进行隐式转换,每个元素必须从参数列表中进行隐式转换:
std::tuple<A, B>
test2B()
{
return {A(), A()}; // ok each element has implicit ctor
}
std::tuple<A, C>
test2C()
{
return {A(), A()}; // error, C(A) is explicit
}
我应该强调:目前这是一个libc ++扩展。
<强>更新强>
chico提出了一个很好的建议,我更新了这个答案:
自从给出了答案以来,DanielKrügler写了一篇paper并于今年四月将其提交给布里斯托尔的C ++委员会。虽然该文件很受欢迎,但在本周进行了审查,将其投入当前的工作草案。
<强>更新强>
丹尼尔的提议现在是current working draft的一部分。现在,libc ++实现已成为下一个C ++标准(我们希望的C ++ 17)的标准。