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

看看下面这个例子:

 1 template<typename T>
 2 class Rational{
 3 public:
 4     Rational(const T & numerator, const T & denominator);
 5     const T numerator()const;
 6     const T denominator() const;
 7 };
 8 template<typename T>
 9 const Rational<T> operator*(const Rational<T>& lhs,
10                             const Rational<T>& rhs);
11 Rational<int> oneHalf(1,2);
12 Rational<int> result = oneHalf*2;

上面的最后一个式子看起来好像能够通过编译,但是实际上不能,因为模版的关系,编译器不会知道我们想调用的是哪个函数。

上面式子能推倒出来,正确的可能就是编译器使用Rational<int>的non-explicit构造函数将2转换,但是编译器进行实参推倒的时候不会将隐式转换放到考虑的范围里面。

而解决上述问题的有效方法就是,不要让operator*需要去进行参数的推倒,而是将其设为Rational的一个friend函数:

 1 template<typename T>
 2 class Rational{
 3 public:
 4     Rational(const T & numerator, const T & denominator);
 5     const T numerator()const;
 6     const T denominator() const;
 7     friend
 8     const Rational operator*(const Rational<T> & lhs,
 9                             const Rational<T> & rhs);
10 };

这样,当oneHalf声明出来的时候,就相当于自动声明出来了上面的operator*,这样的隐式转换同样也来能够成功。

在一个class template里面,template名称可以被用来当作“template何其参数的建议表达形式”,所以说上面的形式和下面的

1   friend
2     const Rational<T> operator*(const Rational<T> & lhs,
3                             const Rational<T> & rhs);

const Rational<T> & rhs);

实际上是相同的。

但实际上上面咋Rational外部去给operator*一个定义是行不通的,因为模板的原因,这个定义必须被放置在类的内部,就像下面这样:

 1 template<typename T>
 2 class Rational{
 3 public:
 4     Rational(const T & numerator, const T & denominator);
 5     const T numerator()const;
 6     const T denominator() const;
 7     friend
 8     const Rational<T> operator*(const Rational<T> & lhs,
 9                             const Rational<T> & rhs)
10     {
11         return Rational(lhs.numerator() * rhs.numerator(),
12                         lhs.denominator() * rhs.denominator());
13     }
14 };

这里的使用friend实际上有其独到的意义:为了让类型转换可以发生在所有的实参身上,需要一个non-member,为了让这个函数被自动具体化,我们需要将他们声明在class内部,而在class内部声明non-member函数的唯一方法就是将他声明称friend。!!

小结:当编写一个class template的时候,起所提供的“与此template相关的”函数支持“所含参数的隐式类型”时,应该将那些函数定义为“class template 内部的”friend函数

时间: 2024-10-13 19:58:29

条款46:需要类型转换的时候请为模板定义非成员函数的相关文章

Effective C++ Item 46 需要类型转换时请为模板定义非成员函数

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:当我们编写一个 class template, 而它所提供之"与此 template 相关的"函数支持"所有参数之隐式类型转换"时,请将那些函数定义为 "class template内部的 friend 函数". 示例: template<typename T> class Rational{ public: Ration

Effective C++笔记_条款46 需要类型转换时请为模板定义非成员函数

看这个章节的时候又跑回去看了一下 条款 24,本章的例子就是基于下面这个例子而来的.在 item 24 中,支持混合运算的示例代码如下: 1 class Rational { 2 public: 3 Rational(int numerator = 0, int denominator = 1); 4 int mumerator() const; 5 int denominator() const; 6 private: 7 int numerator; 8 int denominator; 9

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

1. 条款24举出一个Rational的例子,来说明为什么只有non-member函数才有能力"在所有实参身上实施隐式类型转换".Rational的定义如下: class Rational{ public: Rational(int numerator=0,int denominator=1); int numerator()const; int denominator()const; private: int numerator; int denominator; }; operat

读书笔记 effective c++ Item 46 如果想进行类型转换,在模板内部定义非成员函数

1. 问题的引入——将operator*模板化 Item 24中解释了为什么对于所有参数的隐式类型转换,只有非成员函数是合格的,并且使用了一个为Rational 类创建的operator*函数作为实例.在继续之前建议你先回顾一下这个例子,因为这个条款的讨论是对它的扩展,我们会对Item 24的实例做一些看上去无伤大雅的修改:对Rational和opeartor*同时进行模板化: 1 template<typename T> 2 class Rational { 3 public: 4 Rati

Effective C++ 条款46

本节条款:需要类型转换时请为模板定义非成员函数 这节知识是在条款24的基础上,讲述的有关非成员函数在模板类中(non-member function template)的作用. 我们先看一下条款24讲述的知识核心.条款24讲述了我们如何能实现类的对象在特定条件下的隐式转换问题. 我们先看以下代码: ** 例一: ** #include<iostream> #include<assert.h> using namespace std; class Rational { private

Exceptional C++: [Item 46 Forwarding Functions] [条款46 转发函数]

条款46 转发函数 难度:3 编写转发函数的最好方式是什么?基本答案很简单,但是我们还是可以学到标准定案之前做出的一个微妙的语言变化. 转发函数是将任务转发给其他函数或对象的有用工具,尤其是在高效完成转发的时候. 评论下面的转发函数.你会修改它吗?如果会,怎样修改? // file f.cpp // #include "f.h" /*...*/ bool f( X x ) { return g( x ); } 回答 还记得这个问题的介绍吗?转发函数是将任务转发给其他函数或对象的有用工具

条款25:考虑写出一个不抛异常的swap函数

条款25:考虑写出一个不抛异常的swap函数 swap函数在C++中是一个非常重要的函数,但实现也非常复杂. 看一个缺省的std::swap函数的实现 namespace std { template<typename T> void swap( T& a , T& b) { T temp(a); a = b; b = temp } } ①内置类型的调用 int a = 2; int b =3; std::swap(a, b); cout<<"a:&quo

Effective C++ Item 46 当需要投你非成员函数定义模板

本文senlie原版的,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:当我们编写一个 class template, 而它所提供之"与此 template 相关的"函数支持"全部參数之隐式类型转换"时.请将那些函数定义为 "class template内部的 friend 函数". 演示样例: template<typename T> class Rational{ public: Rati

Effective C++_笔记_条款09_绝不在构造和析构过程中调用virtual函数

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: class Transaction{ 2: public: 3: Transaction(); 4: virtual void LogTransaction() const = 0 ; 5: ... 6: }; 7:  8: Transaction::Transaction() //Base cl