C++ 正在初始化“中的ZeroMQ 2.2消息”;几乎总是自动的”;style希望使用私有构造函数

C++ 正在初始化“中的ZeroMQ 2.2消息”;几乎总是自动的”;style希望使用私有构造函数,c++,c++11,constructor,initialization,zeromq,C++,C++11,Constructor,Initialization,Zeromq,我已经编写了一个使用ZeroMQ的C++11程序 在某一行中,我想创建一条新消息作为局部变量,并使用-style语法将其初始化为名为serialized的向量大小: auto zm = zmq::message_t {serialized.size()}; 在我的机器上(我们称之为机器“A”;使用Clang++3.4.2-13版,也使用g++4.9.1版),这可以很好地编译,而在同事的机器上(“B”;使用Clang++3.5.0-10版),则会发生错误: 错误:调用类“zmq::message

我已经编写了一个使用ZeroMQ的C++11程序

在某一行中,我想创建一条新消息作为局部变量,并使用-style语法将其初始化为名为
serialized
的向量大小:

auto zm = zmq::message_t {serialized.size()};
在我的机器上(我们称之为机器“A”;使用Clang++3.4.2-13版,也使用g++4.9.1版),这可以很好地编译,而在同事的机器上(“B”;使用Clang++3.5.0-10版),则会发生错误:

错误:调用类“zmq::message\t”的私有构造函数
auto zm=zmq::message_t{serialized.size()};
^
/usr/include/zmq.hpp:192:9:注意:此处声明为私有
消息(const message&);
^
两台机器都运行Debian8.0(jessie)。计算机A已安装(ZeroMQ版本4.0.5+dfsg-2),而计算机B上已安装(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上的错误消失了

我的问题是:

  • 我打算调用
    消息(size\t)
    构造函数。为什么有人试图在机器B上使用私有的
    message\u t(const message\u t&)

  • 使错误消失的代码更改将删除赋值运算符。为什么编译器没有抱怨
    void操作符=(const message_t&)
    是私有的,而是
    message_t(const message_t&)

  • 为什么机器A上没有错误,尽管
    message\u t(const message\u t&)
    在那里也是私有的?我想这与
    message\u t(size\u t)
    被声明为
    explicit
    有关,但我不理解这个关键字的效果。(编辑:我最初不知道机器a的版本中有一个移动构造函数,而机器B的版本中不存在该构造函数。)

  • 转向

    进入

    as=调用(不需要的、私有的)复制构造函数

    auto zm = zmq::message_t {serialized.size()};
    
    不是转让, 但是使用move或copy构造函数(可以省略)初始化
    zm
    ,该构造函数应该是可访问的(即使省略)

    按照预期使用
    显式消息(size\t)
    构建临时消息

    我怀疑Clang++版本3.4.2-13中有一个bug,因为您应该与机器B中有相同的错误。(B没有解释此行为的a中的移动操作符)

    是一个变量声明,因此在本例中,=是一个副本初始化,而不是做作,这就是为什么这是被调用的构造函数,而不是做作运算符。
    Explicit关键字意味着构造函数只考虑直接初始化,这与

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

    您可以在这里找到更多详细信息和示例:

    但是为什么第一个语法不会导致机器A出现错误?我认为这不是Clang中的错误,因为它也使用g++版本4.9.1进行编译。(我更新了问题以提及这一点)。@mkrieger1:见。两个(最近的)clang/g++都(正确地)拒绝了代码。所以,如果示例代码适合您,那么就有一个bug。(或者将相关代码隐藏为move构造函数)。这是一个很好的观点。在机器a的ZeroMQ版本中确实有一个移动构造函数和一个移动分配,而在机器B的版本中没有。我已经更新了这个问题。
    explicit
    是否真的在这里起作用?
    explicit
    在这里不起作用
    explicit
    不允许调用
    void foo(message_t)
    使用
    foo(42)
    ,您必须使用
    foo(message_t{42})
    来调用它。是的,我已经知道了。我的问题是为什么会这样,为什么它不是其中一台机器上的错误。
    auto zm = zmq::message_t {serialized.size()};
    
    auto zm = zmq::message_t {serialized.size()};
    
    zmq::message_t zmq {serialized.size()};