假设我有一个看起来像这样的函数:
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>());
}
但是有一个问题,如果In
和In2
是不同类型的迭代器怎么办?例如,char*
vs int*
。取决于In
和In2
,谓词可能在比较期间截断值。例如,如果In
为char*
,则即使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__
扩展名......但我也不喜欢这个想法。有什么办法以符合标准的方式获得净效果?
答案 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_type
与In2
不同的示例),则由客户端而不是您来决定纠正编译时错误。
确保您的算法记录良好,至少可以说:)
答案 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。)