簡體   English   中英

std :: is_base_of用於模板化矢量函數參數

[英]std::is_base_of for templated vector function parameter

我想提供兩個不同的operator>>實現,具體取決於給定類型是否是特殊類型的子類:

class A {};

class B : public A{};
class C {};

template<typename T>
std::istream& operator>>(std::istream& is,
    std::vector<typename std::enable_if<std::is_base_of<A, T>::value>::type>& vec)
{
    std::cout << "Special case called" << std::endl;
    return is;
}

template<typename T>
std::istream& operator>>(std::istream& is,
    std::vector<T>& vec)
{
    std::cout << "General case called" << std::endl;
    return is;
}


void main(int argc, char **argv)
{
    std::vector<A> a;
    std::vector<B> b;
    std::vector<C> c;
    std::stringstream ss("A string");
    ss >> a;
    ss >> b;
    ss >> c;
}

哪個打印

General case called
General case called
General case called

將第二個運算符定義更改為

template<typename T>
std::istream& operator>>(std::istream& is,
    std::vector<typename std::enable_if<!std::is_base_of<A, T>::value>::type>& vec)
{
    std::cout << "General case called" << std::endl;
    return is;
}

不編譯因為

error C2678: binary '>>' : no operator found which takes a left-hand operand of type 'std::stringstream'

所以我可能使用std::enable_if錯了。 但是什么是正確的? 這里有模板化的std::vector有問題嗎?

我不認為std :: enable_if在這里是最想要的位置,我會把它放在返回類型中以啟用SFINAE:

template<typename T>
typename std::enable_if<std::is_base_of<A, T>::value,std::istream>::type& 
operator>>(std::istream& is,std::vector<T>& vec)
{
    std::cout << "Special case called" << std::endl;
    return is;
}

template<typename T>
typename std::enable_if<!std::is_base_of<A, T>::value,std::istream>::type& 
operator>>(std::istream& is,std::vector<T>& vec)
{
    std::cout << "General case called" << std::endl;
    return is;
}

現場演示

@ Biggy的答案正確地證明了一種正確的方法。 這是我發現更具可讀性的替代方案(以及一些小的修正和改進):

template<typename T, typename std::enable_if<std::is_base_of<A, T>{}, int>::type = 0>
std::istream& operator >>(std::istream& is, std::vector<T>& vec) {
    std::cout << "Special case called\n";
    return is;
}

template<typename T, typename std::enable_if<!std::is_base_of<A, T>{}, int>::type = 0>
std::istream& operator >>(std::istream& is, std::vector<T>& vec) {
    std::cout << "General case called\n";
    return is;
}

在線演示

或者更好的是,使用標簽調度:

template<typename T>
std::istream& impl(std::istream& is, std::vector<T>& vec, std::true_type) {
    std::cout << "Special case called\n";
    return is;
}

template<typename T>
std::istream& impl(std::istream& is, std::vector<T>& vec, std::false_type) {
    std::cout << "General case called\n";
    return is;
}

template<typename T>
std::istream& operator >>(std::istream& is, std::vector<T>& vec) {
    return impl(is, vec, std::is_base_of<A, T>{});
}

在線演示

在實踐中,我發現當條件數量很大時后一種方法可以更加可維護,並且導致更容易破譯的錯誤消息。

至於為什么你的代碼不起作用,問題是std::enable_if<std::is_base_of<A, T>::value>::type作為參數類型不是T的可推導上下文,並且有沒有其他參數涉及T來輔助扣除。 因此,當您調用T時,您沒有明確指定T ,因此運算符根本不適合調用,因為T未知。 當你然后把相同的嘗試,SFINAE在其他重載,超載既不可行,你會得到你的錯誤。 一個寬松的經驗法則是:如果您需要typename (與enable_if用法一樣),則您不再處於可推斷的上下文中。

enable_if放在返回類型或默認模板參數中是有效的,因為參數類型(特別是好的和簡單的std::vector<T>& )是T可以推導的。

暫無
暫無

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

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