簡體   English   中英

為什么模板模板參數不能按預期工作?

[英]Why does template template parameters not work as expected?

#include <vector>

template
<
    typename T,
    typename Alloc,
    template<typename, typename> class Left
>
Left<T, Alloc>&&
operator <<(Left<T, Alloc>&& coll, T&& value)
{
    coll.push_back(std::forward<T>(value));
    return std::forward<Left<T, Alloc>>(coll);
}

using namespace std;

int main()
{
    vector<int> c1;
    c1 << int(8);
}

VS 2015的輸出:

錯誤C2678:二進制'<<':未找到采用'std :: vector>類型的左手操作數的運算符(或沒有可接受的轉換)

為什么模板模板參數不能按預期工作?

您的函數接受一個右值引用,但是您傳遞了一個左值-Left Left<T, Alloc>&& 不是轉發引用,因此用std::forward等將其視為不正確。 現在,我們將禁止使用集合rvalue來簡化事情:

template<
    typename T,
    typename Alloc,
    template<typename, typename> class Left
>
Left<T, Alloc>& operator <<(Left<T, Alloc>& coll, T&& value) {
    coll.push_back(std::forward<T>(value));
    return coll;
}

上面的步驟更近了一步,但如果為value傳遞了左value則將不起作用 一種選擇是對Left強制使用正確的參數:

template<
    typename T,
    typename Alloc,
    template<typename, typename> class Left
>
Left<typename std::decay<T>::type, Alloc>&
operator <<(Left<typename std::decay<T>::type, Alloc>& coll, T&& value) {
    coll.push_back(std::forward<T>(value));
    return coll;
}

在線演示

這行得通,但並沒有給我們提供支持集合右值的任何簡便方法。 IMO的正確解決方案是停止使用模板模板,並通過static_assert確認容器的value_typeT匹配,或者如果不匹配,則操作員將SFINAE刪除:

template<typename Coll, typename T>
Coll& operator <<(Coll& coll, T&& value) {
    static_assert(std::is_same<
            typename std::decay<T>::type,
            typename Coll::value_type
        >::value,
        "T does not match Coll::value_type"
    );
    coll.push_back(std::forward<T>(value));
    return coll;
}

在線演示

要么

template<typename Coll, typename T>
typename std::enable_if<std::is_same<
        typename std::decay<T>::type,
        typename Coll::value_type
    >::value,
    Coll&
>::type
operator <<(Coll& coll, T&& value) {
    coll.push_back(std::forward<T>(value));
    return coll;
}

在線演示

完成此操作后,現在如果您決定要支持集合右值,那么這很簡單。 static_assert實現為例:

template<typename Coll, typename T>
Coll&& operator <<(Coll&& coll, T&& value) {
    static_assert(std::is_same<
            typename std::decay<T>::type,
            typename std::decay<Coll>::type::value_type
        >::value,
        "T does not match Coll::value_type"
    );
    coll.push_back(std::forward<T>(value));
    return std::forward<Coll>(coll);
}

在線演示

注意,上述實現只允許使用 Coll::value_type 完全匹配的運算符,但允許將任何可轉換為 Coll::value_type內容合理地實現–實施此方法,只需將std::is_same替換為std::is_convertible

暫無
暫無

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

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