模板函数的名称修饰

以前一直认为,C++函数的命名取决于函数名以及参数列表。例如,
int foo(int a, float b)g++ 做mangling之后foo的名字为 _Z3fooif
其中: _Z     --  reserved
            3foo  --  the function name "foo"
            i         --  1st parameter, int type
            f         --  2nd parameter, float type
如果我们同时定义

int foo(int a, float b) {
    return 0;
}

float foo(int a, float b) {
    return 0;
}
则程序会因重复定义foo(int, float)而无法通过编译:
#g++ simple.cc -o simple

simple.cc: In function ‘float foo(int, float)’:
simple.cc:6:25: error: new declaration ‘float foo(int, float)’
 float foo(int a, float b) {
                         ^
simple.cc:2:5: error: ambiguates old declaration ‘int foo(int, float)’
 int foo(int a, float b) {

今天在写一个factory的时候,意识到上述修饰规则并不适用于模板函数。模板函数可以具有相同的函数名及参数列表。
这里贴一个非常精简的factory实现(代码部分可跳过)。
Register方法接受BaseType类型的注册,构建string到BaseType到的映射。
Create方法在构造BaseType实例时,根据一个用户给出的string来创建对应类型的实例:

#include <iostream>
#include <string>
#include <memory>
#include <map>
 
class BaseType {
 public:
    virtual ~BaseType() {}
    virtual std::string& Name() = 0;
};
 
template <typename T>
class Type1 : public BaseType {
 public:
    virtual ~Type1() {}
    Type1(std::string &name) : name_(name) {}
    Type1(BaseType &base_type) : name_(base_type.Name()) {}
 
    virtual std::string& Name() {
        return name_;
    }
 
 private:
    T somedata_;
    std::string name_;
};
 
class Factory {
 public:
    template <typename T>
    void Register(std::string name) {
        std::shared_ptr<BaseType> newtype(new T(name));
        prototypes_[name] = newtype;
    }
 
    template <typename T>
    std::shared_ptr<T> Create(std::string name) {
        std::shared_ptr<BaseType> instance(new T(*prototypes_[name]));
        return std::dynamic_pointer_cast<T>(instance);
    }
 
 private:
    std::map<std::string, std::shared_ptr<BaseType>> prototypes_;
};
 
int main() {
    Factory factory;
    factory.Register<Type1<int>>("Type1_int");
    factory.Register<Type1<float>>("Type1_float");
 
    std::shared_ptr<Type1<int>> type_int
        = factory.Create<Type1<int>>("Type1_int");
    std::shared_ptr<Type1<float>> type_float
        = factory.Create<Type1<float>>("Type1_float");
 
    std::cout<<type_int->Name()<<std::endl;
    std::cout<<type_float->Name()<<std::endl;
 
    return 0;
}
52和54行的调用会实例化两个Create方法,分别是
std::shared_ptr<Type1<int>> Factory::Create<Type1<int>>(std::string) 和
std::shared_ptr<Type1<float>> Factory::Create<Type1<float>>(std::string)

这两个方法的函数名称"Create"以及参数列表"std::string"完全相同,但是编译器却可以同时创建这两个函数。
这说明这两个方法在做mangling之后其实名字是不一样的。
我们用nm看一下修饰后的名称:

std::shared_ptr<Type1<int>> Factory::Create<Type1<int>>(std::string)
=>  _ZN7Factory6Create I5Type1IiEEE St10shared_ptrIT_ESs

std::shared_ptr<Type1<float>> Factory::Create<Type1<float>>(std::string)
=>  _ZN7Factory6Create I5Type1IfEEE St10shared_ptrIT_ESs

我们发现模板参数(标红部分)和返回值(标蓝部分)参与了名称的修饰。
这里  I     --  template parameter list begin
         E    --  parameter list end
         I5Type1IiEE   --  Type1<int>
         I5Type1IfEE   --  Type1<float>

         St    --  std::
         St10shared_ptrIT_E    --  std::shared_ptr<T>

从这个例子看,C++的函数模板与普通函数重载相比,有更强的描述能力。因此通过模板实例化的方式来实现两个版本的foo(int, float)是可行的:

template <typename T>
T foo(int a, float b) {
    return 0;
}

int main() {
    foo<int>(1, 0);
    foo<float>(1, 0);
};

参考文献
IA64 mangling: http://mentorembedded.github.io/cxx-abi/abi.html#mangling

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值