LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: simon25hk

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

[复制链接]
 楼主| 发表于 2006-9-10 22:37:13 | 显示全部楼层
manphiz,我从图书馆里借来了C++ Templates回来啃,还是不太懂...正在啃+ing
另外,我试着把这个程序放到DevC++里编译不通过,在Visual C++ 6.0也不能通过.
我想问一个问题:Visual C++6.0好像不能很好地实现某些C++的标淮,是吗?
那么,DevC++呢?

因为我还是个Templates的初学者,很多东西都不太懂,希望见谅.

另外帮我看一下这个程序到底错在哪了..我也不太懂呢T_T
  1. #include <cstdlib>
  2. #include <iostream>

  3. #ifndef IFTHENELSE_HPP
  4. #define IFTHENELSE_HPP

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

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

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

  17. #endif

  18. #ifndef PROMOTION_HPP
  19. #define PROMOTION_HPP

  20. template<typename Ta, typename Tb>
  21. class Promotion {
  22.   public:
  23.     typedef typename IfThenElse<(sizeof(Ta))>(sizeof(Tb)),
  24.                                             Ta,
  25.                                             typename IfTheElse<(sizeof(Ta))<(sizeof(Tb)),
  26.                                                                         Tb,
  27.                                                                         void
  28.                                                                        >::ResultT
  29.                                            >::ResultT ResultT;
  30. };

  31. template<>
  32. class Promotion<T,T> {
  33.   public:
  34.     typedef T ResultT;
  35. }

  36. #endif


  37. template<>
  38. class Promotion<char, short> {
  39.   public:
  40.     typedef int ResultT;
  41. };

  42. template<>
  43. class Promotion<short, char> {
  44.   public:
  45.     typedef int ResultT;
  46. };

  47. template<typename T1, typename T2>
  48. Promotion<T1, T2>::ResultT max(T1 lhs, T2 rhs)
  49. {
  50.   return lhs < rhs ? rhs : lhs;
  51. }

  52. using namespace std;

  53. int main(int argc, char *argv[])
  54. {
  55.     int x = 1;
  56.     double y = 0.5;
  57.     cout<< max(x, y)<<endl;
  58.     x = 3;
  59.     y = 4.5;
  60.     cout<< max(x, y)<<endl;
  61.     system("PAUSE");
  62.     return EXIT_SUCCESS;
  63. }
复制代码
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. // 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-10 23:47:04 | 显示全部楼层
仔细看来,manphiz 兄的程序有点小问题,已经帮你做了点修改:
  1. #include <cstdlib>
  2. #include <iostream>
  3. #ifndef IFTHENELSE_HPP
  4. #define IFTHENELSE_HPP
  5. template<bool C, typename T1, typename T2>
  6. class IfThenElse;
  7. template<typename T1, typename T2>
  8. class IfThenElse<true, T1, T2> {
  9.   public:
  10.     typedef T1 ResultT;
  11. };
  12. template<typename T1, typename T2>
  13. class IfThenElse<false, T1, T2> {
  14.   public:
  15.     typedef T2 ResultT;
  16. };
  17. #endif
  18. #ifndef PROMOTION_HPP
  19. #define PROMOTION_HPP
  20. template<typename Ta, typename Tb>
  21. class Promotion {
  22.   public:
  23.     typedef typename IfThenElse<(sizeof(Ta)>sizeof(Tb)),Ta,Tb>::ResultT ResultT;
  24. };
  25. template<typename T>
  26. class Promotion<T,T> {
  27.   public:
  28.     typedef T ResultT;
  29. };
  30. #endif
  31. template<>
  32. class Promotion<char, short> {
  33.   public:
  34.     typedef int ResultT;
  35. };
  36. template<>
  37. class Promotion<short, char> {
  38.   public:
  39.     typedef int ResultT;
  40. };
  41. template<typename T1, typename T2>
  42. typename Promotion<T1, T2>::ResultT max(T1 lhs, T2 rhs)
  43. {
  44.   return lhs < rhs ? rhs : lhs;
  45. }
  46. using namespace std;
  47. int main(int argc, char *argv[])
  48. {
  49.     int x = 1;
  50.     double y = 0.5;
  51.     cout<< max(x, y)<<endl;
  52.     x = 3;
  53.     y = 4.5;
  54.     cout<< max(x, y)<<endl;
  55.     system("PAUSE");
  56.     return EXIT_SUCCESS;
  57. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2006-9-11 00:47:32 | 显示全部楼层
sorry,忘了两个typename,有劳rickxbx兄了...

不过rickxbx兄将Promotion的那个判断简化了,窃以为不应该。毕竟两个类型的变量大小相等并不代表两个类型是相同的,如32位系统上的int和long。因此,struct Promotion的原始形式将两个大小相等的不同类型的返回量定义为void。这种情况下实际上应该对其建立特化,将int和long统一promote到long类型。

以下是再次修改后的版本(亡羊补牢~):
  1. // ifthenelse.hpp
  2. #ifndef IFTHENELSE_HPP
  3. #define IFTHENELSE_HPP
  4. template<bool c, typename Ta, typename Tb>
  5. struct IfThenElse {};
  6. template<typename Ta, typename Tb>
  7. struct IfThenElse<true, Ta, Tb> {
  8.         typedef Ta ResultT;
  9. };
  10. template<typename Ta, typename Tb>
  11. struct IfThenElse<false, Ta, Tb> {
  12.         typedef Tb ResultT;
  13. };
  14. #endif
复制代码
  1. // promotion.hpp
  2. #ifndef PROMOTION_HPP
  3. #define PROMOTION_HPP
  4. #include "ifthenelse.hpp"
  5. template<typename T1, typename T2>
  6. struct Promotion{
  7.         typedef typename IfThenElse<(sizeof(T1)>sizeof(T2)),
  8.                                     T1,
  9.                                     typename IfThenElse<(sizeof(T1)<sizeof(T2)),
  10.                                                         T2,
  11.                                                         void
  12.                                                        >::ResultT
  13.                                    >::ResultT ResultT;
  14. };
  15. template<typename T>
  16. struct Promotion<T, T> {
  17.         typedef T ResultT;
  18. };
  19. #endif
复制代码
  1. // promotion_specialize.hpp
  2. #ifndef PROMOTION_SPECIALIZE_HPP
  3. #define PROMOTION_SPECIALIZE_HPP
  4. #include "promotion.hpp"
  5. #define PROMOTION_SPECIALIZE(T1, T2, RT)        \
  6. template<>                                        \
  7. struct Promotion<T1, T2> {                        \
  8.         typedef RT ResultT;                        \
  9. };                                                \
  10. template<>                                        \
  11. struct Promotion<T2, T1> {                        \
  12.         typedef RT ResultT;                        \
  13. };
  14. PROMOTION_SPECIALIZE(char, short, int);
  15. PROMOTION_SPECIALIZE(int, long, long);
  16. PROMOTION_SPECIALIZE(int, float, double);
  17. // Add yours here
  18. #endif
复制代码
  1. // test.cpp
  2. #include <iostream>
  3. #include "promotion_specialize.hpp"
  4. template<typename T1, typename T2>
  5. typename Promotion<T1, T2>::ResultT max(T1 lhs, T2 rhs)
  6. {
  7.         return lhs < rhs ? rhs : lhs;
  8. }
  9. int main()
  10. {
  11.         char a = 1;
  12.         short b = 12;
  13.         std::cout << max(a, b) << std::endl;
  14.         int c = 10;
  15.         long d = 20;
  16.         std::cout << max(c, d) << std::endl;
  17.         int e = 100;
  18.         float f = 1e10;
  19.         std::cout << max(e, f) << std::endl;
  20. }
复制代码

另:有关编译器:
Visual C++ 6是化石编译器,不支持大部分高级模板特性,如模板偏特化等。如果使用模板编程,请不要使用Visual C++ 6。VC7.1(2003)以后的版本可以考虑。
Dev-Cpp实际上是个编辑器。它默认使用MinGW gcc 3.4.2版本编译器。gcc 3.4以后对模板的支持比较好,可以放心使用。

C++ Templates是本很复杂的书,希望能仔细研究,必会大有收获。
回复 支持 反对

使用道具 举报

发表于 2006-9-11 04:17:09 | 显示全部楼层
收藏学习中...
回复 支持 反对

使用道具 举报

发表于 2006-9-11 10:33:02 | 显示全部楼层
trait技法呀……奇技淫巧,叹为观止。
回复 支持 反对

使用道具 举报

发表于 2006-9-11 19:21:07 | 显示全部楼层
Post by manphiz
不过rickxbx兄将Promotion的那个判断简化了,窃以为不应该。

嗯,确实是这样

讨论了半天,貌似把楼主给冷落了,其实楼主的问题在我的能力范围内是不可解的,原因很简单,返回值类型必须在编译时就确定,而两个(或多个)值的大小关系一般要到运行时才明了(立即数要除外),所以那个问题看似无解
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-9-11 21:48:10 | 显示全部楼层
我想请教一下:
在Templates书中说要记录基本类型的提升,需要针对一系列基本类型进行特化

//traits/promote3.hpp  建立一个宏

#define MK_PROMOTION(T1,T2,Tr)                  \
     template<>class Promotion<T1,T2>     {    \
           public:                                                   \
           typedef Tr ResutlT;                                \
  };                                                                   \
      template<>class Promotion<T2,T1>     {   \
           public:                                                   \
           typedef Tr ResutlT;                               \
  };                                                                  \


//traits/promote4.hpp

MK_PROMOTION( bool, char ,int )
MK_PROMOTION( bool, unsigned char, int )
.....
.....
要枚举出几十种

为什么一定要针对这些基本类型进行类型提升,不特化可以吗?
如果按照我首贴的要求,根据那个参数大返回值就是那是那个大的.
if 我的参数有两个 bool , int
   如果bool值大于int ,应该返回bool型,但是提升后,不就变成int型了? 不解?
回复 支持 反对

使用道具 举报

发表于 2006-9-11 22:40:52 | 显示全部楼层
类型提升实际上是模拟C/C++语言中的隐式类型转换规则。
以整数类型为例:当两个不同类型的整数进行算数运算时,为了使表达式避免复杂的类型转换语句,便定义了一套隐式类型转换规则。小整数类型(如short)能用大整数类型表示(如int),因此便定义了从小到大类型的类型转换,通常成为类型提升。这是符合习惯的。又为了整数类型值也可以用于判断语句,而这在大部分情况下不会产生歧义,因此存在整数类型到bool类型的隐式转换。
Promotion Trait因为建立在类型大小比较的基础上,因此大部分情况符合这些规则,但在基本类型提升上不符合C/C++标准的习惯,如<int类型到int,long以上数值类型到double。这种情况下便需要通过特化来描述这些行为。
当然,楼主可以根据实际需要进行取舍,保留需要的部分即可。
回复 支持 反对

使用道具 举报

发表于 2006-9-11 23:30:31 | 显示全部楼层
Post by manphiz
类型提升实际上是模拟C/C++语言中的隐式类型转换规则。
以整数类型为例:当两个不同类型的整数进行算数运算时,为了使表达式避免复杂的类型转换语句,便定义了一套隐式类型转换规则。小整数类型(如short)能用大整数类型表示(如int),因此便定义了从小到大类型的类型转换,通常成为类型提升。这是符合习惯的。又为了整数类型值也可以用于判断语句,而这在大部分情况下不会产生歧义,因此存在整数类型到bool类型的隐式转换。
Promotion Trait因为建立在类型大小比较的基础上,因此大部分情况符合这些规则,但在基本类型提升上不符合C/C++标准的习惯,如<int类型到int,long以上数值类型到double。这种情况下便需要通过特化来描述这些行为。
当然,楼主可以根据实际需要进行取舍,保留需要的部分即可。


很明显,你没有搞清楚楼主的目的,楼主要的不是类型提升之类的东西(因为有可能会"降"),而是想..... (请看楼主的原帖)
回复 支持 反对

使用道具 举报

发表于 2006-9-11 23:34:50 | 显示全部楼层
Post by rickxbx
很明显,你没有搞清楚楼主的目的,楼主要的不是类型提升之类的东西(因为有可能会"降"),而是想..... (请看楼主的原帖)
呵呵,其实我明白楼主的目的。但是我想告诉楼主的是,他所希望达到的效果是不符合习惯的,而类型提升才是预想的效果。
(又没有一次说清楚,呵呵)
回复 支持 反对

使用道具 举报

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

本版积分规则

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