以 "almost always auto" 样式初始化 ZeroMQ 2.2 消息要使用私有构造函数

Initializing ZeroMQ 2.2 message in "almost always auto" style wants to use private constructor

我写了一个使用 ZeroMQ 的 C++11 程序。

在一个特定的行中,我想创建一个新消息作为局部变量,并使用名为 serialized 的向量的大小对其进行初始化,使用 "almost always auto" 风格的语法:

auto zm = zmq::message_t {serialized.size()};

这在我的机器上编译得很好(我们称之为机器“A”;使用 Clang++ 版本 3.4.2-13 并且还使用 g++ 版本 4.9.1),而在同事的机器上(“B”;使用 Clang++版本 3.5.0-10) 出现错误:

error: calling a private constructor of class 'zmq::message_t'
    auto zm = zmq::message_t {serialized.size()};
              ^
/usr/include/zmq.hpp:192:9: note: declared private here
        message_t (const message_t&);
        ^

两台机器都是运行 Debian 8.0 (jessie)。机器 A 安装了 libzmq3-dev installed (ZeroMQ version 4.0.5+dfsg-2), while on machine B libzmq-dev(ZeroMQ 版本 2.2.0+dfsg-6)。在比较各自包中包含的两个版本 zmq.hpp 时,以下部分可能与此问题相关。

在机器 A 上:

class message_t
{
    // ...

public:
    inline explicit message_t (size_t size_)
    {
        int rc = zmq_msg_init_size (&msg, size_);
        if (rc != 0)
            throw error_t ();
    }

    // ...

#ifdef ZMQ_HAS_RVALUE_REFS
    inline message_t (message_t &&rhs) : msg (rhs.msg)
    {   
        int rc = zmq_msg_init (&rhs.msg);
        if (rc != 0)
            throw error_t (); 
    }   

    inline message_t &operator = (message_t &&rhs)
    {   
        std::swap (msg, rhs.msg);
        return *this;
    }   
#endif

    // ...

private:
    zmq_msg_t msg;
    message_t (const message_t&);
    void operator = (const message_t&);
};

在机器 B 上:

class message_t : private zmq_msg_t
{
    // ...

public:
    inline message_t (size_t size_)
    {
        int rc = zmq_msg_init_size (this, size_);
        if (rc != 0)
            throw error_t ();
    }

    // no move constructor/move assignment

    // ...

private:
    message_t (const message_t&);
    void operator = (const message_t&);
};

当我将我的代码更改为这个时

zmq::message_t zmq {serialized.size()};

机器 B 上的错误消失了。

我的问题是:

  1. 我打算调用 message_t (size_t) 构造函数。为什么会尝试在机器 B 上使用私有的 message_t (const message_t&)

  2. 使错误消失的代码更改删除了赋值运算符。为什么编译器不抱怨 void operator = (const message_t&) 是私有的,而是抱怨 message_t (const message_t&)?

  3. 为什么机器A上没有错误,虽然message_t (const message_t&)在那里也是私有的?我想这与声明 message_t (size_t) explicit 有关,但我不明白这个关键字的作用。 (edit: 原来我不知道A机版本有move构造函数,B机版本没有。)

auto zm = zmq::message_t {serialized.size()};

进入

izmq::message_t zm {serialized.size()};

因为 = 调用(不需要的,私有的)复制构造函数

正在关注

auto zm = zmq::message_t {serialized.size()};

不是作业, 但是使用移动或复制构造函数(可能被省略)初始化 zm 应该可以访问(即使它被省略)。

如预期的那样explicit message_t (size_t)构建了临时文件。

我怀疑 Clang++ 版本 3.4.2-13 中存在错误,因为您应该遇到与机器 B 中相同的错误。(A 中 B 没有的移动运算符解释这种行为)。

auto zm = zmq::message_t {serialized.size()};

是一个变量声明,所以在这种情况下 = 是一个复制初始化而不是矫揉造作,这就是为什么这是被调用的构造函数而不是矫揉造作的运算符。
显式关键字意味着构造函数仅被考虑用于直接初始化,

就是这种情况
zmq::message_t zmq {serialized.size()};

您可以在此处找到更多详细信息和示例:http://en.cppreference.com/w/cpp/language/explicit