无法复制std :: vector <std :: function <void()=“”>&gt;使用统一初始化。这是正确的吗?</std :: function <void>

时间:2012-12-30 01:46:36

标签: c++ c++11 initializer-list

以下代码无法在GCC 4.7.2或Clang 3.2中编译:

#include <vector>
#include <functional>

int main()
{
   std::vector<std::function<void()>> a;
   std::vector<std::function<void()>> b{a};
}

问题是编译器会尝试使用initializer_list创建b,显然它应该只是调用复制构造函数。然而,这似乎是期望的行为,因为标准认为initializer_list构造函数应该优先。

此代码适用于其他std :: vector,但对于std :: function,编译器无法知道您是否需要initializer_list构造函数或其他构造函数。

似乎没有办法解决它,如果是这种情况,那么你永远不能在模板化代码中使用统一初始化。这将是一个巨大的耻辱。

另一方面,Visual Studio(2012年11月CTP)并没有抱怨这一点。但是暂时的initializer_list支持并不是很好,所以它可能是一个bug。

2 个答案:

答案 0 :(得分:11)

这是LWG 2132,这还不是一个缺陷报告,但有明确的共识(和实施经验)来解决它。标准说std::function的构造函数将接受任何类型,因为初始化列表构造函数总是优于其他构造函数(如果它可行),您的代码会尝试从std::initializer_list<std::function<void()>>构造一个向量从对象a初始化的单个元素。然后会导致错误,因为虽然您可以从std::function<void()>构造a,但结果对象不可调用。

换句话说,问题是std::function有一个不受约束的模板构造函数,允许从任何类型转换。这会导致您的情况出现问题,因为如果可行,初始化列表构造函数优先于其他构造函数,而无约束function构造函数意味着始终可以从任何类型创建initializer_list<function<void()>>,因此初始化列表构造函数总是可行的。

建议的2132解决方案阻止从不可调用类型构造std::function,因此初始化列表构造函数不可行,而是调用vector复制构造函数。 I implemented that resolution for GCC 4.8,它已经在Clang的libc ++库中实现了。

答案 1 :(得分:5)

我看不出有任何理由不应该编译,gcc(版本4.8.0 20121111)和clang(版本3.3(trunk 171007))编译代码。也就是说,“统一初始化”远非统一:在调用构造函数时,肯定会出现无法使用大括号的情况。