3

Следующий код - это моя первая попытка C++ 11 по довольно печатанию итерируемых контейнеров. Он использует функцию параметра по умолчанию шаблона функции.неоднозначный оператор << для шаблонной перегрузки

#include <ostream> 
#include <string> 
#include <utility> 

template <typename T> 
void print(std::ostream &o, T const &t) { o<< t; } 

void print(std::ostream &o, std::string const &s){ o<< '"'<< s<< '"'; } 

template <typename K, typename V> 
void print(std::ostream &o, std::pair<K, V> const &p) 
{ 
    o<< '{'; print(o, p.first); 
    o<< ": "; print(o, p.second); 
    o<< '}'; 
} 

template <typename C, typename I= typename C::const_iterator> 
std::ostream &operator<< (std::ostream &o, C const &c) 
{ 
    o<< '['; 
    if(c.empty()) return o<< ']'; 
    I b= c.begin(), e= c.end(); -- e; 
    for(; b!= e; ++ b) 
    { 
    print(o, *b); 
    o<< ", "; 
    } 
    print(o, *b); 
    return o<< ']'; 
} 

Он отлично работает на контейнерах, контейнер контейнеров и т.д. С одним исключением:

std::cout<< std::string("wtf"); 

компиляции с г ++ 4.7/8 брейки говоря ambiguous operator<<.

Есть ли какие-либо исправления для этого кода, чтобы избежать двусмысленности?

+0

Поскольку 'станд :: string' имеет' const_iterator ', ваш шаблон' operator <<' является совпадением. –

+0

@VaughnCato да, я хотел бы, чтобы std :: basic_string перегрузка была предпочтительной, если это было возможно. – nurettin

+0

Вы можете использовать 'enable_if' для отключения вашей перегрузки, когда' C' является строкой. –

ответ

2

Вы можете использовать std::enable_if, чтобы отключить перегрузку в случае строки:

template <typename C, typename I= typename C::const_iterator> 
typename std::enable_if<!std::is_same<C,std::string>::value,std::ostream>::type & 
    operator<< (std::ostream &o, C const &c) 
{ 
    o<< '['; 
    if(c.empty()) return o<< ']'; 
    I b= c.begin(), e= c.end(); -- e; 
    for(; b!= e; ++ b) 
    { 
    print(o, *b); 
    o<< ", "; 
    } 
    print(o, *b); 
    return o<< ']'; 
} 

или сделать его более обобщенно:

template <typename T> 
struct is_string : std::false_type {}; 

template <typename Char,typename Allocator> 
struct is_string<std::basic_string<Char,Allocator> > : std::true_type {}; 

template <typename C, typename I= typename C::const_iterator> 
typename std::enable_if<!is_string<C>::value,std::ostream>::type & 
    operator<< (std::ostream &o, C const &c) 
{ 
    o<< '['; 
    if(c.empty()) return o<< ']'; 
    I b= c.begin(), e= c.end(); -- e; 
    for(; b!= e; ++ b) 
    { 
    print(o, *b); 
    o<< ", "; 
    } 
    print(o, *b); 
    return o<< ']'; 
} 
+0

хороший вызов, я хотел сделать это без enable_ifs (следовательно, параметр по умолчанию), но вы все равно дали правильный ответ. – nurettin

Смежные вопросы