2009-08-29 63 views
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,謂詞可以在其比較期間截斷值。例如,如果Inchar*,那麼即使In2int*,也會調用std::less<char>

::operator<有兩個參數時,編譯器能夠推導出正確的類型,並且適用標準類型提升規則。然而,當選擇一個謂詞傳遞給函數時,沒有機會發生這種情況。 是否有一些巧妙的方法可以根據InIn2找出我想要傳遞std::less<>的哪個版本?

編輯:

下面的例子說明了這個問題:

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 

EDIT

考慮這件事後,我真的想是要能夠做這樣的事情:

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

我想我可以使用gcc的__typeof__擴展......,但是我不喜歡這個想法無論是。任何方式以標準一致的方式獲得淨效應?

回答

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>()); 
+0

是的,到目前爲止,非均勻少模板似乎是解決方案。實際上,我想知道爲什麼'std :: less'(或者所有的binary_function比較器)不能取2個模板參數。似乎這是在所有情況下使'std :: less'的行爲類似於operator <的唯一方法。 – 2009-08-31 15:19:30

0

如果對算法的要求是這樣的:Invalue_type不一定是相同的In2的值類型,那麼我會離開這個模板參數,你有他們;否則它們應該是一樣的。

無論它們是相同的還是不同的,它都取決於例程的客戶端,以滿足您允許指定的算法的先決條件。例如,在此您可以要求value_typeInIn2value_type相同。如果這是真的,那麼函數應該按照客戶的期望進行編譯並且是正確的。

在這種情況下,您可以傳遞std::less<T>這兩個模板類型的value_type的實例,您應該沒問題。但是,如果客戶端違反了該前提條件(如上面提供的示例中charint不同),那麼糾正編譯時錯誤將由客戶端決定,而不是由您決定。

確保你的算法充分證明,至少可以說:)

+0

但它是合理的算法接受迭代器不同,但兼容的類型(如在我的例子,一個char可以比作一個int)。但'std :: less (some_int,some_char);'是錯誤,但是':: operator <(some_int,some_char)'不是。 – 2009-08-29 05:38:00

+0

您可以使用像Boost的靜態斷言庫這樣的工具在編譯時聲明類型是相同的。 – fbrereto 2009-08-29 05:42:57

+0

我想讓他們**不**是一樣的。基本上,我想要一個合適的方式來選擇一個謂詞,使其像':: operator <'一樣(如果可能的話,它將提升較小的類型)。 – 2009-08-29 05:44:29

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。)

相關問題