簡體   English   中英

C ++重載std :: count_if()作為謂詞和值

[英]C++ overloading std::count_if() for a predicate and a value

考慮下面的代碼,其目的是重載std::count_if()以使用容器作為參數,而不是通常的輸入和輸出迭代器。

// overload for call with predicate
template<typename Cont_T, typename Pred_T>
typename std::iterator_traits<typename Cont_T::iterator>::difference_type 
count_if(const Cont_T& c, Pred_T p) {
    return std::count_if(c.begin(), c.end(), p);
}

// overload for call with value
template<typename Cont_T, typename T = typename Cont_T::value_type>
typename std::iterator_traits<typename Cont_T::iterator>::difference_type
count_if(const Cont_T& c, const T& val) {
    return std::count_if(c.begin(), c.end(), val);
}

int main() {
   using namespace std;

   vector<int> v{1,2,3};
   count_if(v, 2);          // ambiguous call

   return 0;
}

結果是編譯器錯誤,表明調用不明確。

有沒有辦法使這項工作?

如果使用標准容器( value_type 1 ),則可以嘗試:

// overload for call with predicate
template<typename Cont_T>
typename std::iterator_traits<typename Cont_T::iterator>::difference_type 
count_if(const Cont_T& c, std::function<bool(typename Cont_T::value_type)> p) {
    return std::count_if(c.begin(), c.end(), p);
}

// overload for call with value
template<typename Cont_T>
typename std::iterator_traits<typename Cont_T::iterator>::difference_type
count_if(const Cont_T& c, const typename Cont_T::value_type& val) {
    return std::count(c.begin(), c.end(), val);
}

通過強制第二個參數的類型(而不使其成為模板參數),可以避免歧義。 但是,我可能不會這樣做,而是堅持使用count / count_if的標准版本。

1如果不能依賴Cont_T::value_type ,則可以用更“通用”的decltype(*c.begin()) )或類似的東西代替它。

有了SFINAE,您可以

namespace helper
{

    using std::begin;
    using std::end;

    struct low_priority {};
    struct high_priority : low_priority {};

    template<typename Cont, typename Pred>
    decltype(true == std::declval<Pred>()(*begin(std::declval<const Cont&>())),
             void(), std::size_t{})
    count_if(const Cont& c, Pred&& p, high_priority)
    {
        return std::count_if(begin(c), end(c), std::forward<Pred>(p));
    }

    template<typename Cont, typename T>
    decltype(*begin(std::declval<const Cont&>()) == std::declval<T>(),
             void(), std::size_t{})
    count_if(const Cont& c, T&& val, low_priority) {
        return std::count(begin(c), end(c), std::forward<T>(val));
    }

}

template <typename Cont, typename T>
std::size_t count_if(const Cont& c, T&& val_or_pred)
{
    return helper::count_if(c, std::forward<T>(val_or_pred), helper::high_priority{});
}

作為獎勵,這也適用於C數組。

演示

兩個錯誤:您混淆了std :: count()和std :: count_if(),並且使用錯了。

首先,std :: count_if()需要謂詞,而不是值。 謂詞是一個函數(或lambda表達式),返回一個布爾值是否應計算參數。 您想輸入一個值,因此需要使用std:count()代替。

其次,您不能僅傳遞向量。 相反,您需要傳遞由兩個迭代器指定的范圍。

請在此頁面上查看std :: count()和std :: count_if()的工作示例: http ://en.cppreference.com/w/cpp/algorithm/count

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM