[英]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.