由ZeroMQ一处编译错误,引申的一个C++编译规范

最近在编译ZeroMQ源码时, 出现了一个编译错误,其本质是涉及到C++的一个编译规范.编译出错的源码文件为:

/*
    Copyright (c) 2007 FastMQ Inc.

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __ZMQ_ENCODER_HPP_INCLUDED__
#define __ZMQ_ENCODER_HPP_INCLUDED__

#include <assert.h>
#include <algorithm>

#include "dispatcher_proxy.hpp"
#include "cmsg.hpp"

namespace zmq
{

    template <typename T> class encoder_t
    {
    public:

        encoder_t (dispatcher_proxy_t *proxy_, int source_thread_id_,
              size_t chunk_size_) :
            proxy (proxy_),
            source_thread_id (source_thread_id_),
            chunk_size (chunk_size_)
        {
            init_cmsg (msg);
        }

        ~encoder_t ()
        {
            free_cmsg (msg);
        }

        //  The chunk after being used should be deallocated
        //  using standard 'free' function
        bool read (unsigned char **data_, size_t *size_)
        {
            unsigned char *chunk = (unsigned char*) malloc (chunk_size);
            assert (chunk);
            size_t pos = 0;

            while (true) {
                if (to_write) {
                    size_t to_copy = std::min (to_write, chunk_size - pos);
                    memcpy (chunk + pos, write_pos, to_copy);
                    pos += to_copy;
                    write_pos += to_copy;
                    to_write -= to_copy;
                }
                else {
                    if (!((static_cast <T*> (this)->*next) ()))
                    {
                        *data_ = chunk;
                        *size_ = pos;
                        return false;
                    }
                    continue;
                }
                if (pos == chunk_size)
                    break;
            }
            *data_ = chunk;
            *size_ = pos;
            return true;
        }

    protected:

        typedef bool (T::*parse_step_t) ();

        inline void next_step (void *write_pos_, size_t to_write_,
            parse_step_t next_)
        {
            write_pos = (unsigned char*) write_pos_;
            to_write = to_write_;
            next = next_;
        }

        inline bool fetch ()
        {
            //  TODO: review the deallocation of msg (w.r.t. zero copy)
            free_cmsg (msg);
            init_cmsg (msg);
            return proxy->read (source_thread_id, &msg);
        }

        cmsg_t msg;

    private:
        dispatcher_proxy_t *proxy;
        int source_thread_id;
        size_t chunk_size;
        unsigned char *write_pos;
        size_t to_write;
        parse_step_t next;
    };

}

#endif

使用make编译源码工程时,出现如下错误:

encoder.hpp:61:60: error: there are no arguments to 'memcpy' that depend on a template parameter, so a declaration of 'memcpy' must be available [-fpermissive]
                     memcpy (chunk + pos, write_pos, to_copy);
                                                            ^
encoder.hpp:61:60: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)

C++标准要求,对于依赖于模板参数的名字,将在模板类(或函数)实例化的时候进行名字查找,对于不依赖模板参数的名字,将搜索当前的定义. 举例说明, 如下类定义:

template <typename T>
class C {
    T t;
    int get() {
        return t.getValue();
    }
};

成员函数get依赖于模板参数T,因此对于get的实现是否正确,只有在模板类C实例化并调用get函数的时候才知道.如果模板类C没有实例化,这个类定义肯定是编译正确的,因为编译器无从判断模板参数T是否具有成员函数getValue.这个情况是典型的场景. 更需要注意的是具有继承关系的场景,举例如下:

template <typename T> class B {
    int f(){return 0;};
};

 template <typename T> class D : public B<T> {
    int get() { return f(); }
 };

这里子类D的get方法调用父类中的方法f,而f是不依赖其模板参数的名字,编译器将搜索f定义,而不是对应父类中的名字.所以编译器会产生类似前文一样的错误.为了更清晰的表明子类使用父类中的成员函数,需要使用模板参数依赖的方法来访问父类的成员函数.有2种形式可以消除这个错误,使用

int get() { return B<T>::f(); }

或者

int get() { return this->f(); }

当然,正如编译器错误信息提示,可以使用-fpermissive 标志让编译器接受这种代码格式,但是这不是推荐的行为.

回到开始ZeroMQ的编译错误,函数memcpy没有依赖类encoder_t的模板参数,但是不同的是,这里不能用依赖模板参数的形式访问memcpy,因为memcpy是个库函数,而不是模板类的成员函数,这里的问题本质是没要找到memcpy的定义,缺少了相应的头文件string.h, 因此包含该头文件即可.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值