【问题标题】:Can't copy a std::vector<std::function<void ()>> using uniform initialization. Is this correct?无法使用统一初始化复制 std::vector<std::function<void ()>>。这个对吗?
【发布时间】:2012-12-31 02:53:13
【问题描述】:

以下代码无法在 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};
}

问题是编译器将尝试使用初始化器列表创建 b,而显然它应该只是调用复制构造函数。然而,这似乎是理想的行为,因为标准规定 initializer_list 构造函数应该优先。

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

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

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

【问题讨论】:

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


    【解决方案1】:

    这是LWG 2132,它还不是缺陷报告,但有明确的共识(和实施经验)来修复它。标准规定std::function 的构造函数将接受任何类型,因此,如果可行,初始化列表构造函数总是优于其他构造函数,因此您的代码尝试从 std::initializer_list&lt;std::function&lt;void()&gt;&gt; 构造一个向量,其中单个元素从对象a。这会导致错误,因为尽管您可以从 a 构造 std::function&lt;void()&gt;,但生成的对象不可调用。

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

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

    【讨论】:

    • 感谢您的回答。 LWG 2132 链接实际上讨论了一个相似但不同的问题,恰好也解决了这个问题。这意味着该问题将仅针对 std::function 解决,而不针对具有模板化构造函数的其他类型。我认为我对统一初始化的新规则是“尽可能使用它,除非对象具有 initializer_list 构造函数。然后仅在需要该构造函数时使用它。”这也意味着你不能在模板代码中使用它。
    • 我更喜欢“不要编写允许从任何类型进行隐式转换的无约束构造函数模板”的规则。如果您不创建这样的类型,那么对于尝试将您的类型与具有初始化列表构造函数的类一起使用的人来说,您不会造成问题。标准库没有遵循该规则,但已针对 std::function 进行了修复。
    【解决方案2】:

    我看不出任何不应该编译的原因,并且 gcc(版本 4.8.0 20121111)和 clang(版本 3.3(主干 171007))都编译了代码。也就是说,“统一初始化”远非统一:在调用构造函数时肯定存在不能使用大括号的情况。

    【讨论】:

    • g++ 4.7.2 (4.7.2-5ubuntu1) 不编译代码。非常奇怪的编译器错误信息:pastebin.com/b1mcbYRq
    • @leemes 因为问题以“以下代码无法在 GCC 4.7.2 或 Clang 3.2 中编译:”打开,我假设 OP 知道这一点(这可能是问题的原因首先)。
    • @WhozCraig 是的,但他没有提供编译器消息。这就是我首先发布此评论的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 2017-04-17
    • 2017-04-04
    • 1970-01-01
    • 2022-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多