(C++ Std 学习) —— 重载函数的地址

27 篇文章 0 订阅
23 篇文章 0 订阅

(C++ Std 学习) —— 重载函数的地址

概述和背景

     在日常学习工作中,很多时候都会用到函数,还要理解函数的地址是如何生成和使用的,不过绝大部分而言都是直接使用类对象指针来调用对应的函数即可,这个过程在内存中其实就是找到对应的对象的其实地址,然后加上该函数在该类对象中的函数地址片偏移量即可找到对应的函数的一个过程。那么,C++Std中又是如何定义关于函数地址的重载的呢,都有哪些细节呢?这就是我这篇文章学习的过程的由来和目的了,希望能够通过记录这篇文章加深自己对于函数的地址的使用方式的理解。

参考文本和自行翻译

在这里插入图片描述

    除了函数调用表达式之外,如果发生重载解析,重载函数的名称可能出现在以下7种上下文中:

  1. 对象或引用声明中的初始值设定项;
  2. 在赋值表达式的右侧;
  3. 作为函数调用参数;
  4. 作为用户定义的运算符参数;
  5. 返回语句;
  6. 显式强制转换或静态强制转换参数;
  7. 非类型模板参数;

     在每种上下文中,重载函数的名称前面可以加上操作符的地址,并且可以用一组冗余的括号括起来。
     在所有这些上下文中,从重载集中选择的函数是其类型与目标所期望的指向函数的指针、指向函数的引用或指向成员函数类型的指针匹配的函数:正在初始化的对象或引用、赋值的左侧、函数或运算符参数,函数的返回类型、强制转换的目标类型或模板参数的类型。

     函数的参数类型和返回类型必须与目标完全匹配,不考虑隐式转换(例如,在初始化指向返回基指针的函数的指针时,返回指向派生的指针的函数不会被选中)。

     如果函数名命名一个函数模板,那么首先,先尝试模板参数推导,如果推导成功,则生成一个模板用来处理模板专门化,并将其添加到重载集合中进行考虑。不满足关联约束的所有函数都将从集合中删除。(C++ 20)如果集合中的一个以上的函数与目标匹配,并且至少一个函数是非模板的,那么就不用考虑模板专用性。对于任何一个非模板函数,其中一个比另一个约束更大,因此从集合中删除较少的约束函数(因为C++ 20)。如果所有剩余的候选者都是模板专业化的,那么如果有更专业化的候选者,则删除不太专业化的候选者。如果在删除后还有一个以上的候选人留下来,那么这个程序就是格式错误的。

案例代码分析

在这里插入图片描述

int f(int) { return 1; }
int f(double) { return 2; }
// g 的参数是两个函数地址的应用,传进来可以调用该函数。
// The parameter of g is the application of two function addresses, and the function can be called when passed in.
void g( int(&f1)(int), int(*f2)(double) ) {}
// 作为模板参数传入函数地址
// Pass in the function address as a template parameter
template< int(*F)(int) >
struct Templ {};
 
struct Foo {
    int mf(int) { return 3; }
    int mf(double) { return 4; }
};
 
struct Emp {
    void operator<<(int (*)(double)) {}
};
 
int main()
{
    // 1. initialization
    int (*pf)(double) = f; // selects int f(double)
    int (&rf)(int) = f; // selects int f(int)
    int (Foo::*mpf)(int) = &Foo::mf; // selects int mf(int)
 
    // 2. assignment
    pf = nullptr;
    pf = &f; // selects int f(double)
 
    // 3. function argument
    g(f, f); // selects int f(int) for the 1st argument
             // and int f(double) for the second
 
    // 4. user-defined operator
    Emp{} << f; //selects int f(double)
 
    // 5. return value
    auto foo = []() -> int (*)(int) {
        return f; // selects int f(int)
    };
 
    // 6. cast
    auto p = static_cast<int(*)(int)>(f); // selects int f(int)
 
    // 7. template argument
    Templ<f> t;  // selects int f(int)
}

OSG的代码中使用分析

在这里插入图片描述

namespace osg
{

// 定义模板类,这个类会使用到传进来的模板函数指针
template<typename T>
class TemplateAttributeDispatch : public AttributeDispatch
{
    public:
		// 定义函数指针的类型,是使用的模板数据作为参数
        typedef void (GL_APIENTRY * F) (const T*);

        TemplateAttributeDispatch(F functionPtr, unsigned int stride):
            _functionPtr(functionPtr), _stride(stride), _array(0) {}

        virtual void assign(const GLvoid* array)
        {
            _array = reinterpret_cast<const T*>(array);
        }

        virtual void operator () (unsigned int pos)
        {
        	// 使用函数指针来访问对应的函数地址
            _functionPtr(&(_array[pos*_stride]));
        }
		// 定义函数指针对象,用来调用对应的函数的地址内容。
        F               _functionPtr;
        unsigned int    _stride;
        const T*        _array;
};

// 这个类的使用方式与上面的类似
template<typename I, typename T>
class TemplateTargetAttributeDispatch : public AttributeDispatch
{
    public:

        typedef void (GL_APIENTRY * F) (I, const T*);

        TemplateTargetAttributeDispatch(I target, F functionPtr, unsigned int stride):
            _functionPtr(functionPtr), _target(target), _stride(stride), _array(0) {}

        virtual void assign(const GLvoid* array)
        {
            _array = reinterpret_cast<const T*>(array);
        }

        virtual void operator () (unsigned int pos)
        {
            _functionPtr(_target, &(_array[pos * _stride]));
        }

        F                       _functionPtr;
        I                       _target;
        unsigned int            _stride;
        const T*                _array;
};


class AttributeDispatchMap
{
public:

    AttributeDispatchMap() {}

    template<typename T>
    void assign(Array::Type type, void (GL_APIENTRY *functionPtr) (const T*), unsigned int stride)
    {
        if ((unsigned int)type >= _attributeDispatchList.size()) _attributeDispatchList.resize(type+1);
        _attributeDispatchList[type] = functionPtr ? new TemplateAttributeDispatch<T>(functionPtr, stride) : 0;
    }
	// 传入函数指针来作为访问函数地址的使用手段
    template<typename I, typename T>
    void targetAssign(I target, Array::Type type, void (GL_APIENTRY *functionPtr) (I, const T*), unsigned int stride)
    {
        if ((unsigned int)type >= _attributeDispatchList.size()) _attributeDispatchList.resize(type+1);
        _attributeDispatchList[type] = functionPtr ? new TemplateTargetAttributeDispatch<I,T>(target, functionPtr, stride) : 0;
    }

    AttributeDispatch* dispatcher(const Array* array)
    {
        // OSG_NOTICE<<"dispatcher("<<array<<")"<<std::endl;

        if (!array) return 0;

        Array::Type type = array->getType();
        AttributeDispatch* dispatcher = 0;

        // OSG_NOTICE<<"    array->getType()="<<type<<std::endl;
        // OSG_NOTICE<<"    _attributeDispatchList.size()="<<_attributeDispatchList.size()<<std::endl;

        if ((unsigned int)type<_attributeDispatchList.size())
        {
            dispatcher = _attributeDispatchList[array->getType()].get();
        }

        if (dispatcher)
        {
            // OSG_NOTICE<<"   returning dispatcher="<<dispatcher<<std::endl;
            dispatcher->assign(array->getDataPointer());
            return dispatcher;
        }
        else
        {
            // OSG_NOTICE<<"   no dispatcher found"<<std::endl;
            return 0;
        }
    }

    typedef std::vector< ref_ptr<AttributeDispatch> >  AttributeDispatchList;
    AttributeDispatchList               _attributeDispatchList;
};


//
//  With inidices
//
// 下面这些就是利用上面的类传入对应的函数地址的一种方式的过程

AttributeDispatch* AttributeDispatchers::vertexAttribDispatcher(unsigned int unit, Array* array)
{
    if (unit>=_vertexAttribDispatchers.size()) assignVertexAttribDispatchers(unit);
    return _vertexAttribDispatchers[unit]->dispatcher(array);
}

void AttributeDispatchers::assignVertexAttribDispatchers(unsigned int unit)
{
    GLExtensions* extensions = _state->get<GLExtensions>();

    for(unsigned int i=_vertexAttribDispatchers.size(); i<=unit; ++i)
    {
        _vertexAttribDispatchers.push_back(new AttributeDispatchMap());
        AttributeDispatchMap& vertexAttribDispatcher = *_vertexAttribDispatchers[i];
        vertexAttribDispatcher.targetAssign<GLuint, GLfloat>(i, Array::FloatArrayType, extensions->glVertexAttrib1fv, 1);
        vertexAttribDispatcher.targetAssign<GLuint, GLfloat>(i, Array::Vec2ArrayType, extensions->glVertexAttrib2fv, 2);
        vertexAttribDispatcher.targetAssign<GLuint, GLfloat>(i, Array::Vec3ArrayType, extensions->glVertexAttrib3fv, 3);
        vertexAttribDispatcher.targetAssign<GLuint, GLfloat>(i, Array::Vec4ArrayType, extensions->glVertexAttrib4fv, 4);
    }
}

个人格言

用心去感受你自己需要坚持的生活,未来慢慢会给你答案的。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值