随笔-90  评论-947  文章-0  trackbacks-0

有个需求,能否做到实现一个类似这样的函数:

template <typename T1, typename T2>
XXX Min(T1 t1, T2 t2)
{
    return (t1 < t2 ? t1 : t2);
}

其中 XXX 是我们要推导出的类型。

以下是一个失败的尝试。

我记得 Loki 里有关于如何判断某个类型能否隐式转换为另一个类型的东西,大意如下:

template <typename T, typename U>
class Conversion
{
private:
    typedef char Small;
    class Big { char XXX[2]; };
    static Small Test(U);
    static Big Test(...);
    static T MakeT();
public:
    enum
    {
        Exists = (sizeof(Test(MakeT())) == sizeof(Small)),
    };
};

如此,Conversion<T, U>::Exists 就能判断 T 到 U 的转换是否存在了。

然后再搞个选择:

template <bool Condition, typename TypeIfTrue, typename TypeIfFalse>
struct Select
{
    typedef TypeIfFalse Type;
};

template <typename TypeIfTrue, typename TypeIfFalse>
struct Select<true, TypeIfTrue, TypeIfFalse>
{
    typedef TypeIfTrue Type;
};

最后,再来个:

struct NullType;

template <typename T, typename U>
struct CommonType
{
    typedef typename Select<Conversion<T, U>::exists,
                                        U,
                                        typename Select<Conversion<U, T>::exists,
                                                                T,
                                                                NullType>::Type
                                       >::Type Type;
};

那么 CommonType<T1, T2> 就是 T1 和 T2 之间哪个是他们的共有类型了。

测试:

int main()
{
    CommonType<int, double>::Type m = 0;

    return 0;
}

调试,确认 m 是 double 的。但是反过来写 CommonType<double, int>::Type m = 0;,m 却是 int 的。

这说明这套机制一开始就有问题,Test(U) 和 Test(…) 两个重载函数中,Test(…) 不会在需要 double 转 int 时胜出。这是第一个问题。

第二个问题,当写下如下代码的时候:

template <typename T1, typename T2>
CommonType<T1, T2>::Type Min(T1 t1, T2 t2)
{
    return (t1 < t2 ? t1 : t2);
}

编译无法通过。原因是返回类型中的 CommonType 中的模板参数 T、U 无法接受此时还不能确定的 T1、T2。

(更正:不是这个原因,返回类型前加 typename 即可。现在问题还是第一个问题。)

请教各位,有没有什么方法做到?欢迎指教~

C++ 0x 中就能很方便做到了:

template <typename T1, typename T2>
auto Min(T1 t1, T2 t2) -> decltype(t1 + t2)
{
    return (t1 < t2 ? t1 : t2);
}

int main()
{
    int a = 2;
    double b = 1.0;
    auto m = Min(a, b);

    return 0;
}

posted on 2011-03-29 21:27 溪流 阅读(1872) 评论(16)  编辑 收藏 引用 所属分类: C++

评论:
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-29 23:38 | so
我不知道0x的新概念。撇开不谈。
请问一个min/max函数怎么根据两个参数推倒返回值类型呢? 因为参数的比较是运行时概念。
另外,实现出来有什么作用呢?  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 00:36 | 陈梓瀚(vczh)
你都返回xxx?t1:t2了,那么T1跟T2只能相等。  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 03:32 | gbb21
理论上是不可能的事情,C++的类型是静态的,对运行时确定的类型无法推倒~  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 08:15 | 周星星
auto Min(T1 t1, T2 t2) -> decltype(t1 + t2)
应该是
[] Min(T1 t1, T2 t2) -> decltype(t1 + t2)
吧  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 08:31 | 溪流
@so
我不需要参数的数值大小,只需要知道类型信息啊,编译期可以知道  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 08:32 | 溪流
@陈梓瀚(vczh)
比如 T1 = int, T2 = double,我期望返回类型是 double  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 08:33 | 溪流
@gbb21
这还没到运行时啊,模板函数特化的时候就知道了啊  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 08:33 | 溪流
@周星星
不一定要 lambda 啊,单单一个普通函数就可以了,就像我原文里写的那样  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 09:31 | 周星星
我在g++4.5中试了一下你的代码,是正确的,用[]反而不对。
但我看维基百科中是这么写的(和lambda语法类似,但不是lambda),在http://zh.wikipedia.org/wiki/C++0x 中搜索 “另一种的函数语法”  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 09:45 | FF
关于第一个问题,是C++内建类型的隐式转换引起的,这需要禁止C++内建类型的隐式转换,如果不能禁用用,就对所有内建类型重载Test函数,这样能够避免内建类型的转换。

关于第二个问题,我觉得有点奇怪,我建议Select的第一个模板参数改为typename T_, 然后分别特化struct true_flag 和struct false_flag  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 14:20 | 空明流转
你这个问题无解。  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 14:22 | 空明流转
@溪流
不知道。  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 14:25 | 溪流
@空明流转
我现在倒是有了个不太完美的解法:

// 判断 T 到 U 的转换是否存在
template <typename T, typename U>
class Conversion
{
private:
typedef char Small;
class Big { char XXX[2]; };
static Small Test(U);
static Big Test(...);
static T MakeT();
public:
enum
{
Exists = (sizeof(Test(MakeT())) == sizeof(Small)),
};
};

// 以上对内置类型的判断还是不够给力,
// 比如给出 T = int,U = double,它认为可转换;反过来,它还是认为可转换,只是多了个 warning 而已。
// 所幸,这些内置类型是有限的,我们可以采用人肉的方法,两两组合,分别给出偏特化版本。
// 简洁起见,仅列出 int 和 double 两个。
template <>
class Conversion<int, double>
{
public:
enum
{
Exists = true,
};
};

template <>
class Conversion<double, int>
{
public:
enum
{
Exists = false,
};
};


template <bool Condition, typename TypeIfTrue, typename TypeIfFalse>
struct Select
{
typedef TypeIfFalse Type;
};

template <typename TypeIfTrue, typename TypeIfFalse>
struct Select<true, TypeIfTrue, TypeIfFalse>
{
typedef TypeIfTrue Type;
};

struct NullType;

template <typename T, typename U>
struct CommonType
{
typedef typename Select<Conversion<T, U>::Exists,
U,
typename Select<Conversion<U, T>::Exists,
T,
NullType>::Type
>::Type Type;
};

template <typename T1, typename T2>
typename CommonType<T1, T2>::Type Min(T1 t1, T2 t2)
{
return (t1 < t2 ? t1 : t2);
}

int main()
{
int a = 0;
double b = 1;
CommonType<int, double>::Type m1 = Min(a, b);
CommonType<double, int>::Type m2 = Min(a, b);
int m3 = Min(a, b);
double m4 = Min(a, b);

return 0;
}


只是。。。太人肉了。。。
  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 15:49 | somebody
template<class T1, class T2>
auto max(const T1 & t1, const T2 & t2)
->decltype(t1 >= t2 ? t1 : t2)
{
return t1 >= t2 ? t1 : t2;
}  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 17:31 | 空明流转
你这个和无解没有任何区别。  回复  更多评论
  
# re: 如何实现一个支持不同类型的 max/min 函数? 2011-03-30 19:49 | 陈昱(CY)
好像内置的都可以隐式转换,先弄个判断是否内置类型的模板,再对内置的类型直接判断类型大小就够了  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理