确定模板类型的正确谓词的方法

时间:2009-08-29 05:12:58

标签: c++ templates predicate

假设我有一个看起来像这样的函数:

template <class In, class In2>
void func(In first, In last, In2 first2);

我希望这个函数调用另一个接受谓词的函数。我最初的直觉是做这样的事情:

template <class In, class In2>
void func(In first, In last, In2 first2) {
    typedef typename std::iterator_traits<In>::value_type T;
    other_func(first, last, first2, std::less<T>());
}

但是有一个问题,如果InIn2是不同类型的迭代器怎么办?例如,char* vs int*。取决于InIn2,谓词可能在比较期间截断值。例如,如果Inchar*,则即使std::less<char>In2,也会调用int*

::operator<给出两个参数时,编译器能够推断出正确的类型,并且适用标准类型提升规则。但是,当选择传递给函数的谓词时,没有机会来实现这一点。 是否有一些聪明的方法可以根据std::less<>In找出我要传递的In2版本?

修改

以下示例说明了问题:

unsigned int x = 0x80000000;
unsigned char y = 1;
std::cout << std::less<unsigned char>()(x, y) << std::endl;
std::cout << std::less<unsigned int>()(x, y) << std::endl;

将输出:

1
0

修改

在考虑之后,我真正想要的是能够做到这样的事情:

typedef typeof(T1() < T2()) T;
other_func(first, last, first2, std::less<T>());

我想我可以使用gcc的__typeof__扩展名......但我也不喜欢这个想法。有什么办法以符合标准的方式获得净效果?

3 个答案:

答案 0 :(得分:2)

我似乎记得在boost中存在这种特征,但在快速搜索后我找不到它。如果你不比我成功,你可以自己构建它,

template <typename T1, typename T2>
struct least_common_promotion;

template <>
struct least_common_promotion<short, int>
{
    typedef int type;
};

但你必须指定一些明确的专业化。 type traits提升库可以帮助您减少数量。

编辑:我感觉很愚蠢,操作需要这样的东西(结果类型取决于操作数类型),但不是谓词(结果类型为bool)。你可以简单地写一下:

template <class T1, T2>
struct unhomogenous_less : public std::binary_function<T1, T2, bool>
{
   bool operator()(T1 const& l, T2 const& r) const
   { return l < r; }
};

...

typedef typename std::iterator_traits<In>::value_type value_type_1;
typedef typename std::iterator_traits<In2>::value_type value_type_2;
other_func(first, last, first2, unhomogenous_less<value_type_1, value_type_2>());

答案 1 :(得分:0)

如果您对算法的要求使得In的{​​{1}}不需要与value_type的值类型相同,那么我会保留模板参数他们;否则他们应该是一样的。

无论它们是相同还是不同,您的例程客户端都必须满足您可以指定的算法的先决条件。例如,您可以要求In2的{​​{1}}与value_type的{​​{1}}相同。如果这是成立的话,那么函数应该编译并且正如客户期望的那样。

在这种情况下,您可以传递任一模板类型In的{​​{1}}实例,您应该没问题。

但是,如果客户端违反了该前提条件(如上面提供的value_typeIn2不同的示例),则由客户端而不是您来决定纠正编译时错误。

确保您的算法记录良好,至少可以说:)

答案 2 :(得分:0)

以SGI旧的std::equal实现为例,STL算法通过使用相同算法的两个版本来处理这种情况:一个使用编译器在编译时推导出的内在<运算符时间,以及采用用户定义的二元谓词,以便用户可以使用他们喜欢的任何类型:

template <class _InputIter1, class _InputIter2>
inline bool equal(_InputIter1 __first1, _InputIter1 __last1,
                  _InputIter2 __first2) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _EqualityComparable);
  __STL_REQUIRES(typename iterator_traits<_InputIter2>::value_type,
                 _EqualityComparable);
  for ( ; __first1 != __last1; ++__first1, ++__first2)
    if (*__first1 != *__first2)
      return false;
  return true;
}

template <class _InputIter1, class _InputIter2, class _BinaryPredicate>
inline bool equal(_InputIter1 __first1, _InputIter1 __last1,
                  _InputIter2 __first2, _BinaryPredicate __binary_pred) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  for ( ; __first1 != __last1; ++__first1, ++__first2)
    if (!__binary_pred(*__first1, *__first2))
      return false;
  return true;
}

(注意:旧的SGI STL代码取自here。)