1

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

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*int*. 根据哪个是In和哪个是In2谓词,可能会在比较期间截断值。例如,即使is an也会调用if Inis char*then 。std::less<char>In2int*

::operator<给定两个参数时,编译器能够推断出正确的类型并应用标准类型提升规则。但是,在选择将谓词传递到函数时,没有透明度才能实现这一点。有没有一些聪明的方法可以根据and确定我想通过哪个版本?std::less<>InIn2

编辑:

下面的例子说明了这个问题:

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__扩展...,但我也不喜欢这个想法。有什么方法可以以符合标准的方式获得这种净效果?

4

3 回答 3

2

我似乎记得在boost中有一个特性,但是在快速搜索后我找不到它。如果你不比我成功,你可以自己建造,

template <typename T1, typename T2>
struct least_common_promotion;

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

但是您必须指定很多明确的专业化。boost的类型特征库或许可以帮助你减少它们的数量。

编辑:我觉得很愚蠢,操作需要这种东西(结果类型取决于操作数类型),而不是谓词(结果类型是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>());
于 2009-08-29T07:57:21.010 回答
0

如果您对算法的要求是In'value_type不必与In2' 值类型相同,那么我将保留模板参数,因为它们是你所拥有的;否则它们应该是相同的。

无论它们是相同还是不同,取决于您的例程的客户端是否满足算法的先决条件,您可以指定这些先决条件。例如,在这里您可以要求value_typeof与ofIn相同。如果这是真的,那么该函数应该按照客户的期望编译并且是正确的。value_typeIn2

在这种情况下,您可以传递任一模板类型的std::less<T>实例value_type,您应该没问题。

但是,如果客户端违反了该前提条件(如您在上面提供的示例中 where charis not the 相同int),那么将由客户端而不是您来纠正编译时错误。

至少可以说,确保您的算法有据可查:)

于 2009-08-29T05:32:41.707 回答
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 代码取自此处。)

于 2009-08-29T06:19:38.197 回答