LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 3128|回复: 21

在C++里面如何用模板动态地根据函数参数来决定返回值类型?

[复制链接]
发表于 2006-9-6 22:36:10 | 显示全部楼层 |阅读模式
例如, 一个max模板,
template <typename T1, typename T2>
??? max(T1 a, T2, b)    //返回值类未知...
{
      if ( a > b)  返回a,且返回类型为T1

}
 楼主| 发表于 2006-9-6 22:37:41 | 显示全部楼层
对不起啊,前面不小心按了提交.....

例如, 一个max模板,
template <typename T1, typename T2>
??? max(T1 a, T2, b)    //返回值类未知...
{
      if ( a > b)  返回a,且返回类型为T1
           else 返回b,且返回类型为T2
}

具体应该怎么实现啊?
回复 支持 反对

使用道具 举报

发表于 2006-9-6 23:54:30 | 显示全部楼层
通常来讲,只有两个同类型的量才能做比较操作,即便是short->int甚至int->double,type promotion也可以保证不需要对两个量分别定义类型。

具体到问题本身,有两个方法:
1、使用指定的返回参数:
  1. template<typename RT, typename T1, typename T2>
  2. RT max(T1 lhs, T2 rhs)
  3. {
  4.   return lhs < rhs ? rhs : lhs;
  5. }
复制代码
而在使用中使用下面比较笨拙的方法。
  1. max<double>(2, 4.3);
复制代码


2、采用模板元编程技巧的promotion trait。
首先设计一个IfThenElse模板:
  1. // ifthenelse.hpp
  2. #ifndef IFTHENELSE_HPP
  3. #define IFTHENELSE_HPP
  4. template<bool C, typename T1, typename T2>
  5. class IfThenElse;
  6. template<typename T1, typename T2>
  7. class IfThenElse<true, T1, T2> {
  8.   public:
  9.     typedef T1 ResultT;
  10. };
  11. template<typename T1, typename T2>
  12. class IfThenElse<false, T1, T2> {
  13.   public:
  14.     typedef T2 ResultT;
  15. };
  16. #endif
复制代码

然后设计promotion trait:
  1. // promotion.hpp
  2. #ifndef PROMOTION_HPP
  3. #define PROMOTION_HPP
  4. #include <ifthenelse.hpp>
  5. template<typename Ta, typename Tb>
  6. class Promotion {
  7.   public:
  8.     typedef typename IfThenElse<(sizeof(Ta))>(sizeof(Tb)),
  9.                                             Ta,
  10.                                             typename IfTheElse<(sizeof(Ta))<(sizeof(Tb)),
  11.                                                                         Tb,
  12.                                                                         void
  13.                                                                        >::ResultT
  14.                                            >::ResultT ResultT;
  15. };
  16. template<>
  17. class Promotion<T,T> {
  18.   public:
  19.     typedef T ResultT;
  20. }
  21. #endif
复制代码
这样基本可以满足类型推广的需要。这样使用:
  1. template<typename T1, typename T2>
  2. Promotion<T1, T2>::ResultT max(T1 lhs, T2 rhs)
  3. {
  4.   return lhs < rhs ? rhs : lhs;
  5. }
复制代码
值得注意的在整型类型的类型推广时不满足标准的规定。比如char,short->int。如果需要的话,需要创建模板特化,例如
  1. template<>
  2. class Promotion<char, short> {
  3.   public:
  4.     typedef int ResultT;
  5. };
  6. template<>
  7. class Promotion<short, char> {
  8.   public:
  9.     typedef int ResultT;
  10. };
复制代码
依此类推。

参考
C++ Templates: The Complete Guide, David Vandevoorde, Nicolai M. Josuttis

修改了几下,请见谅
回复 支持 反对

使用道具 举报

发表于 2006-9-7 00:08:18 | 显示全部楼层
应该是很难实现的。
1、模板本身没有所谓“动态”的概念,它只是编译时根据实参进行具现化而已。
2、模板不会根据返回值类型进行推演,从而有效具现化。

个人见解,仅供参考。

你可以看看《C++ Templates : Complete Guide》
回复 支持 反对

使用道具 举报

发表于 2006-9-7 00:13:41 | 显示全部楼层
Post by manphiz

有两个变通方法:
1、使用指定的返回参数:

  1. template<typename RT, typename T1, typename T2>
  2. RT max(T1 lhs, T2 rhs)
  3. {
  4.   return lhs < rhs ? rhs : lhs;
  5. }
复制代码

而在使用中使用下面比较笨拙的方法。

  1. max<double>(2, 4.3);
复制代码


用另一个模板参数做返回类型,还是根据type promotion的吧。

2、将数值本身作为模板参数:
采用模板元编程技巧的promotion trait

这个还不太了解,学习ing
回复 支持 反对

使用道具 举报

发表于 2006-9-7 00:14:56 | 显示全部楼层
Post by manphiz
通常来讲,只有两个同类型的量才能做比较操作,即便是short->int甚至int->double,type promotion也可以保证不需要对两个量分别定义类型。

具体到问题本身,有两个方法:
1、使用指定的返回参数:

  1. template<typename RT, typename T1, typename T2>
  2. RT max(T1 lhs, T2 rhs)
  3. {
  4.   return lhs < rhs ? rhs : lhs;
  5. }
复制代码

而在使用中使用下面比较笨拙的方法。

  1. max<double>(2, 4.3);
复制代码



2、采用模板元编程技巧的promotion trait。
首先设计一个IfThenElse模板:

  1. // ifthenelse.hpp
  2. #ifndef IFTHENELSE_HPP
  3. #define IFTHENELSE_HPP

  4. template<bool C, typename T1, typename T2>
  5. class IfThenElse;

  6. template<typename T1, typename T2>
  7. class IfThenElse<true, T1, T2> {
  8.   public:
  9.     typedef T1 ResultT;
  10. };

  11. template<typename T1, typename T2>
  12. class IfThenElse<false, T1, T2> {
  13.   public:
  14.     typedef T2 ResultT;
  15. };

  16. #endif
复制代码


然后设计promotion trait:

  1. #ifndef PROMOTION_HPP
  2. #define PROMOTION_HPP

  3. #include <ifthenelse.hpp>
  4. template<typename Ta, typename Tb>
  5. class Promotion {
  6.   public:
  7.     typedef typename IfThenElse<(sizeof(Ta))>(sizeof(Tb)),
  8.                                             Ta,
  9.                                             typename IfTheElse<(sizeof(Ta))<(sizeof(Tb)),
  10.                                                                         Tb,
  11.                                                                         void
  12.                                                                        >::ResultT
  13.                                            >::ResultT ResultT;
  14. };

  15. template<>
  16. class Promotion<T,T> {
  17.   public:
  18.     typedef T ResultT;
  19. }

  20. #endif
复制代码

这样基本可以满足类型推广的需要。这样使用:

  1. template<typename T1, typename T2>
  2. Promotion<T1, T2> max(T1 lhs, T2 rhs)
  3. {
  4.   return lhs < rhs ? rhs : lhs;
  5. }
复制代码


强。学习ing~ :2cool
回复 支持 反对

使用道具 举报

发表于 2006-9-7 00:19:23 | 显示全部楼层
Post by Lolita
  1. template<typename T1, typename T2>
  2. Promotion<T1, T2>[color=red]::ResultT[/color] max(T1 lhs, T2 rhs)
  3. {
  4.   return lhs < rhs ? rhs : lhs;
  5. }
复制代码
严重疏忽,不好意思~
回复 支持 反对

使用道具 举报

发表于 2006-9-7 08:19:04 | 显示全部楼层
Modern C++ Design(C++ 设计新思维) 一书中把cpp的模板机制用的出神入化(呵呵,有点夸张),推荐一读.

btw:
通常来讲,只有两个同类型的量才能做比较操作
却不尽然,想cpp的操作符重载用的越来越多,不同类型之间的比较也很正常
回复 支持 反对

使用道具 举报

发表于 2006-9-7 08:40:45 | 显示全部楼层
Post by rickxbx
想cpp的操作符重载用的越来越多,不同类型之间的比较也很正常
呵呵,又表述不清,被斑斑抓到了
其实想说的是进行比较的两个量多少应该据有相同或近似的性质,例如都是数值,或者都在一个继承体系中,因此大部分情况下两个量之间会存在隐式类型转换的可能。而这种情况下即使不使用两个类型也可以借助隐式转换完成比较。当然这样做无法避免类型推广,不过多数情况下这样的行为是可以接受的。

不过经斑斑一提醒,想到了promotion trait的默认行为在处理用户定义类型的时候可能会产生错误。因为它的类型推广思路是基于基本类型的,将类型的大小作为类型推广的标度,而用户定义类型的大小和类型推广方向通常无关,甚至会返回void。因此如果将promotion trait用于用户定义类型,最好还是建立特化的版本,以非预期的行为。
Post by rickxbx
Modern C++ Design(C++ 设计新思维) 一书中把cpp的模板机制用的出神入化(呵呵,有点夸张),推荐一读.
呵呵,这个可是惊世骇俗的大作,不过需要设计模式的知识。先学习着prerequiste……
回复 支持 反对

使用道具 举报

发表于 2006-9-7 09:01:25 | 显示全部楼层
Post by manphiz

呵呵,这个可是惊世骇俗的大作,不过需要设计模式的知识。先学习着prerequiste……

哎,c++的惊世骇俗作品太多了,看得爽也看得累:comp
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表