std :: is_base_of用于模板化矢量函数参数

时间:2017-01-19 09:34:19

标签: c++ c++11 templates std

我希望提供new AuthenticationRequest { // ... Connection = "Database-Connection", Username = vm.EmailAddress, Password = vm.Password } 的两种不同实现,具体取决于给定类型是否是特殊类型的子类:

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在这里有问题吗?

2 个答案:

答案 0 :(得分:8)

我不认为std :: enable_if在这里是最理想的位置,我会把它放在返回类型中以启用SFINAE:

session.getUserMedia({ audio: true, video: {mozMediaSource: 'screen'}).
then(successCallback).
catch(errorCallback);

live demo

答案 1 :(得分:2)

@ 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;
}

Online Demo

或者更好的是,使用标签调度:

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>{});
}

Online Demo

在实践中,当条件数量很大时,我发现后一种方法更易于维护,并且会导致更容易破译的错误消息。

至于为什么你的代码不起作用,问题是std::enable_if<std::is_base_of<A, T>::value>::type作为参数类型不是T的可推导上下文,而且没有其他参数涉及T来辅助扣除。因此,当您调用T时,您不会明确指定T,因为typename未知,运算符根本不是合格的候选者。当你把相同的尝试-SFINAE置于另一个过载时, 过载是否可行并且你得到错误。一个宽松的经验法则是:如果您需要enable_if(与enable_if用法一样),则您不再处于可推断的背景中。

std::vector<T>&放在返回类型或默认模板参数中的作用是有效的,因为参数类型(特别是简单的T)是private可以推导出来的。< / p>