EffectiveC++学习笔记-条款46

条款46 需要类型转换时请为模板定义非成员函数

需要类型转换时请为模板定义非成员函数
首先为什么类似于operator 这样的重载运算符要定义成非成员函数,主要是为了保证混合乘法2 Variant或者Variant * 2都可以通过编译,但是2不能同时进行隐式类型转换成某个Variant,再作this用。

所以我们一般将之定义成友元函数,像下面这样:

class Variant
{
public:
    Variant(const int& value = 0) {}

    friend const Variant operator* (const Variant&lhs, const Variant& rhs);
};

const Variant operator* (const Variant&lhs, const Variant& rhs) 
{
    return Variant();
}

//使用方式
Variant val(1);             //ok
Variant result = val * 1;   //ok
result = 2 * val;           //ok

现在引入模板,可以像下面这样写,注意这里的operator*是一个独立的模板函数:

template<typename T>
class Variant
{
public:
    Variant(const T& value = 0) {}
};

template<typename T>
const Variant<T> operator* (const Variant<T>&lhs, const Variant<T>& rhs)
{
    return Variant<T>();
}

但是这次不能通过编译并且在vs2015下的报错信息:

C2784   “const Variant<T> operator *(const Variant<T> &,const Variant<T> &)”: 未能从“int”为“const Variant<T> &”推导 模板 参数 

原因是编译器推导T出现了困难,val * 1在编译器看来,可以由a是Variant将T推导成int,但是1是什么,理想情况下编译器会尝试将它先转换成一个Variant,并将T推导成int,但事实上编译器在“T推导过程中从不将隐式类型转换函数纳入考虑”。所以无论是val * 1还是1 * val 都是不能通过编译的,一句话,隐式转换+推导T不能被同时被编译器接受。

解决问题的思路便接着产生,编译器既然不能同时接受这两个过程,就让它们事先满足好一个条件,再由编译器执行另一个过程好了。

如果把这个operator*放在template class里面,也就是先在生成模板类的那一步就定下T,这样编译器只要执行隐式转换这一步就可以了。

因此我们可以这样来改:

template<typename T>
class Variant
{
public:
    Variant(const T& value = 0) {}

    friend const Variant<T> operator* (const Variant<T>&lhs, const Variant<T>& rhs);
};

在类中加一个友元。

我们添加了一个友元函数的声明,果然编译通过了,但链接时又报错了,原因是链接器找不到operator*的定义,这里又要说模板类中的一个特殊情况了,它不同与普通的类,模板类的友元函数只能在类中实现,所以要把函数体部分移至到类内,像下面这样:

template<typename T>
class Variant
{
public:
    Variant(const T& value = 0) {}

    friend const Variant<T> operator* (const Variant<T>&lhs, const Variant<T>& rhs)
    {
        return Variant<T>();
    }
};

这下编译和链接都没有问题了。这里还要说一下,就是移至类内后,T的标识符可以不写了。

operator*里面只有一句话,但如果friend函数里面的东西太多了,可以定义一个辅助方法,比如Doxxx(),这个Doxxx可以放在类外去实现,Doxxx本身不支持混合乘法(2 * Variant或者Variant* 2),但由于在operator*里面已经进行了隐式类型转换,所以到Doxxx()这一级是没有问题的。

总结
当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“class template内部的friend函数”。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值