[英]std::is_base_of for templated vector function parameter
I want to provide two different implementations of an operator>>
depending on whether the given type is a subclass of a special type: 我想提供两个不同的
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;
}
Which prints 哪个打印
General case called
General case called
General case called
Changing the second operator definition to 将第二个运算符定义更改为
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;
}
Does not compile because of 不编译因为
error C2678: binary '>>' : no operator found which takes a left-hand operand of type 'std::stringstream'
So I am probably using std::enable_if
wrong. 所以我可能使用
std::enable_if
错了。 But what is correct? 但是什么是正确的? Are there problems with the templated
std::vector
here? 这里有模板化的
std::vector
有问题吗?
I don't think the std::enable_if is in the most desired position here, I would put it in the return type to enable SFINAE: 我不认为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's answer correctly demonstrates one way to do this properly. @ Biggy的答案正确地证明了一种正确的方法。 Here's an alternative that I find a bit more readable (along with some minor corrections and improvements):
这是我发现更具可读性的替代方案(以及一些小的修正和改进):
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;
}
Or better yet, using tag dispatching: 或者更好的是,使用标签调度:
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>{});
}
In practice I've found the latter approach to be much more maintainable when the number of conditions is large, and result in more easily-deciphered error messages. 在实践中,我发现当条件数量很大时后一种方法可以更加可维护,并且导致更容易破译的错误消息。
As to why your code doesn't work, the problem is that std::enable_if<std::is_base_of<A, T>::value>::type
as a parameter type is not a deducible context for T
, and there is no other parameter involving T
to aide deduction. 至于为什么你的代码不起作用,问题是
std::enable_if<std::is_base_of<A, T>::value>::type
作为参数类型不是T
的可推导上下文,并且有没有其他参数涉及T
来辅助扣除。 So because you don't explicitly specify T
when you call it, the operator is simply not an eligible candidate to invoke because T
is not known. 因此,当您调用
T
时,您没有明确指定T
,因此运算符根本不适合调用,因为T
未知。 When you then put the same attempted-SFINAE in the other overload, neither overload is viable and you get your error. 当你然后把相同的尝试,SFINAE在其他重载,超载既不可行,你会得到你的错误。 A loose rule of thumb is: if you need
typename
(as with the enable_if
usage), you are no longer in a deducible context. 一个宽松的经验法则是:如果您需要
typename
(与enable_if
用法一样),则您不再处于可推断的上下文中。
Putting the enable_if
in the return type or as a defaulted template parameter instead works because the parameter types (specifically the nice and simple std::vector<T>&
) are such that T
is deducible. 将
enable_if
放在返回类型或默认模板参数中是有效的,因为参数类型(特别是好的和简单的std::vector<T>&
)是T
可以推导的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.