【发布时间】:2014-05-18 15:41:41
【问题描述】:
我偶然发现了 C++11 引入的新 std::pair 构造函数的一个令人惊讶的行为。我在使用std::pair<int, std::atomic<int>> 时观察到了这个问题,并且它发生了,因为std::atomic 既不可复制也不可移动。在以下代码中,为了简化,我将std::atomic<int> 替换为foobar。
以下代码编译良好,使用 GCC-4.9 和 Clang-3.5(有和没有 libc++):
struct foobar
{
foobar(int) { } // implicit conversion
// foobar(const foobar&) = delete;
};
std::pair<int, foobar> p{1, 2};
这种行为是预期的。但是,当我删除foobar 的复制构造函数时,编译失败。它适用于分段构造,但我认为这不是必需的,因为从int 到foobar 的隐式转换。我指的是具有以下签名的构造函数:
template <typename U, typename V>
pair(U&& u, V&& v);
你能解释一下,为什么 pair 构造函数如此严格,并且不允许对不可复制/不可移动类型进行隐式转换吗?
【问题讨论】:
-
@KerrekSB:我不明白你的意见。在我的示例中,两个成员变量都直接从
int&&初始化。不涉及 foobar 或 pair 的复制构造函数。 -
嗯,我可能搞错了。我正在调查。
-
所以,我尝试用我自制的配对类复制这个,但没有成功。我查看了错误,它指向 GCC 实现并提到了DR 811;奇怪的是,重载是
template <typename U1, typename = [some enable_if]> pair(U1 &&, const T2 &),它最终会生成一个副本(因为它构造了一个临时绑定到第二个参数)。但它不应该! -
我认为这是一个 dup :) 让我看看...问题是标准需要
is_convertible,这令人惊讶地需要可移动性。 stackoverflow.com/q/21405674/420683 -
@dyp:无论哪种方式,我认为这都不是问题:OP 的代码应该 会失败,而且确实会失败。 GCC 通过直接初始化而不是副本传递第一个参数这一事实并没有减少这一点。