0

Я бы хотел иметь operator>>() перегрузки для любого типа «base» и для любого типа контейнера. Это то, что я до сих пор:Как заставить оператора >> (C <T>) перегрузка для соответствия контейнеру?

typedef uintmax_t my_t; 
template <typename T> 
std::istringstream &operator>>(std::istringstream &iss, T &v) 
{ 
    static my_t um = 6009; 
    v = um++; 
    return iss; 
} 

template <template <class> class C, typename T> 
std::istringstream &operator>>(std::istringstream &iss, C<T> &c) 
{ 
    for (typename C<T>::iterator it = c.begin(); it != c.end(); ++it) 
     iss >> *it; 
    return iss; 
} 

int main() 
{ 
    std::vector<uint32_t> vi(3); 
    std::istringstream iss; 
    iss >> vi; 
    for (std::vector<uint32_t>::iterator it = vi.begin(); it != vi.end(); ++it) 
     std::cout << *it << std::endl; 
} 

компилируется и работает, как ожидалось с GCC, но даже не компилируется на VS2015. Последний соответствует оператору >> в операторе iss >> vi; с первой перегрузкой базового типа, которая запускает другие ошибки компиляции. Как написать шаблон operator>>() для неконтейнерных типов и шаблон для типов контейнеров (без необходимости специализации для каждого типа контейнера), который компилируется с GCC и VS2015?

+1

Это не должно компилироваться нигде. Какую версию GCC вы используете? –

+0

Интересно .. Я не могу это сделать для компиляции на g ++ 5.1.0 - как вы его смогли скомпилировать на своей версии gcc? – Alejandro

+0

Здесь он находится на [codepad.org] (http://codepad.org/juUAvEP6). Говорят, что это [g ++ 4.1.2] (http://codepad.org/about). – plong

ответ

5

operator>> перегрузка, которую вы написали, предназначена для шаблона шаблона шаблона (C) с одним аргументом шаблона (T). Тем не менее, std::vector объявлен как:

template< 
    class T, 
    class Allocator = std::allocator<T> 
> class vector; 

Второй аргумент шаблона может быть по умолчанию, но он все еще там. Таким образом, std::vector<uint32_t> не может соответствовать C<T> - поэтому единственная жизнеспособная перегрузка - это шаблон общей функции, который вы написали, который не будет компилироваться, потому что вы не можете назначить std::uintmax_tvector.

Для того, чтобы ваша функция, чтобы принять vector, вы должны соответствовать шаблону шаблона декларации - это означает, принять второй аргумент типа:

template <template <class, class> class C, typename T1, typename T2> 
std::istringstream &operator>>(std::istringstream &iss, C<T1,T2> &c) 
{ 
    for (typename C<T1,T2>::iterator it = c.begin(); it != c.end(); ++it) 
     iss >> *it; 
    return iss; 
} 

Это довольно неудовлетворительное решение, хотя. Действительно, мы хотим сопоставить все, что есть контейнер, который мы можем использовать с помощью SFINAE. Так как это C++ 03, проще всего было бы написать тип признака для ли или нет какой-то тип ЬурейеЕ имени iterator:

template <typename T> 
struct is_container { 
    typedef char yes; 

    struct no { 
     char _[2]; 
    }; 

    template <typename U> 
    static yes test(typename U::iterator*); 

    template <typename U> 
    static no test(...); 

    static const bool value = (sizeof(test<T>(0)) == sizeof(yes)); 
}; 

И добавьте наш удобный enable_if:

template <bool, typename > 
struct enable_if { }; 

template <typename T> 
struct enable_if<true, T> { 
    typedef T type; 
}; 

И придерживаться, что тип возвращаемого значения:

template <typename C> 
typename enable_if< 
    is_container<C>::value, 
    std::istringstream& 
>::type 
operator>>(std::istringstream &iss, C& c) 
{ 
    for (typename C::iterator it = c.begin(); it != c.end(); ++it) 
     iss >> *it; 
    return iss; 
} 

Вы должны будете делать противоположное (!is_container<T>::value) для другой перегрузки, так что они не неоднозначным.

+0

Barry, впечатляет, но я получаю те же результаты - работает с g ++, но не с VS2015. Здесь он находится на [codepad.org] (http://codepad.org/d0A5RtVo). – plong

+0

@Barry Кажется, проблема. Если вы определяете перегрузки «контейнер» и «неконтейнер», то «iss >> * it;» в «контейнере» перегрузка будет использовать «неконтейнерный» 'operator >>', а не версию по умолчанию, право ? – SU3

+0

@ SU3, вот что я хочу сделать - использовать мою неконтейную перегрузку - и это то, что делает g ++ 4,1,2; однако VS2015 пытается использовать мою неконтейную перегрузку для 'iss >> vi;' в моей main().Но 'vi' - это контейнер. Он выглядит так, как будто нет элегантного решения. : -/ – plong