请考虑以下代码:
void foo (M&) {}
M m;
foo ({m});
因此,表达式{m}
被视为右值引用,这就是此代码无法编译的原因。
{object}
是否总是生成临时对象,这是真的吗?
如果不是,那么如何确定它何时发生? 如果是,请考虑以下代码:
struct M {};
struct I {
I (M&) {}
};
struct MM {
MM (M& p)
: m (p), i ( {p} )
{}
M& m;
I i;
};
M m;
MM mm {m};
这里完全没有问题,那么第一个示例中的{m}
与第二个示例中的{p}
之间有什么区别?
编译器(GCC 4.8.1)结果(第一个例子):
main.cpp:366:13: error: invalid initialization of non-const reference of type ‘M&’ from an rvalue of type ‘<brace-enclosed initializer list>’
foo ({m});
^
main.cpp:359:6: error: in passing argument 1 of ‘void foo(M&)’
void foo (M&) {}
答案 0 :(得分:2)
{object}
的类型是什么?
这取决于具体情况。在某些情况下,例如在构建具有std::initializer_list
参数的类型时,它将属于std::initializer_list<decltype(object)>
类型。在其他情况下,它将用于初始化聚合或其他类型的成员,在这种情况下,句法形式{object}
不会 类型本身。
{object}
总是生成临时对象,这是真的吗?
不,在你的情况下,它不应该。这是a bug in the C++11 spec与指定列表初始化的子句的排序有关。旧的措辞意味着您的调用导致构造临时(由于非const引用参数而形成不良),但在新规则下,引用绑定到单个初始化列表元素。您的旧编译器实现旧的措辞,而newer compilers实现固定的行为。
这里完全没有问题,那么第一个例子的{m}和第二个例子的{p}有什么区别呢?
不同之处在于{m}
用于初始化M
的{{1}}参数(旧措辞无效),但foo
初始化{p}
会员。因此,I
被视为p
构造函数的参数,绑定到I
参数,并且由于M&
是左值,所以一切都很好,花花公子。 / p>
答案 1 :(得分:0)
{object}总是生成临时对象吗?
否(继续阅读)。
两个片段都有效(您应该使用最新的编译器)并且将成功编译。
{p}
案件属于[over.match.list]/p1
当非聚合类类型T的对象被列表初始化,使得[dcl.init.list]指定根据本节中的规则执行重载解析时,重载决策分两个阶段选择构造函数:
(1.1) 最初,候选函数是类T的初始化列表构造函数([dcl.init.list]),参数列表由初始化列表作为单个参数组成。
<强>(1.2)强> 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类T的所有构造函数,参数列表由初始化列表的元素组成。
具体在(1.2)中,而{m}
是另一种情况的列表初始化。