我为多个模板化类重载operator<<
,例如map
,pair
(见下文),list
。
它们工作得很好,而且用途广泛。每当我需要更具体的内容时,我都会定义其他优先级operator<<
。
但我不能为迭代器做同样的事情。我得到编译错误。我想处理operator<<
的事实是不可靠的,但重点在于使用迭代器。
我做错了什么,或者我想做什么是不可能的?
我现在的代码(在Brian的回答之后)如下所示。请注意,functiov定义中的每一行都会简要记录错误,并在代码下方详细说明。
#include <iostream>
#include <map>
#include <string>
using namespace std;
typedef pair<string, char> pair_t;
typedef map<pair_t::first_type, pair_t::second_type> map_t;
typedef pair<map_t::iterator, bool> retval_insert_t;
// Templated form of overloading << for a pair
template<typename first_class, class second_class>
ostream& operator<<(ostream& os, const pair<first_class, second_class>& p);
// Templated form of overloading << for an iterator ... does not work
template <class T, class = typename iterator_traits<T>::value_type>
ostream& operator<<(ostream& os, T iterator);
int main(void) {
pair_t p2;
p2 = make_pair(string("Fer"), 'C');
map_t grade_list;
retval_insert_t retval = grade_list.insert(p2);
cout << retval.first << endl; // Does not work with a templated <<
return 0;
}
//********************** Overloaded << functions ***************************************
// ***** pair
// Templated form of overloading << for a pair
template<class first_class, class second_class>
ostream& operator<<(ostream& os, const pair<first_class, second_class>& p)
{
os << "(" << p.first << ", " << p.second << ")"; // Compilation error: Ambiguous overload for the first <<
return os;
}
template <class T, class = typename iterator_traits<T>::value_type>
ostream& operator<<(ostream& os, T iterator)
{
os << iterator; // No compilation error, but segmentation fault
os << *iterator; // Compilation error if uncommenting: Cannot bind
//cout << "Testing" << endl; // Compilation error if uncommenting: Ambiguous overload for the first <<
cout << 1 << endl;
return os;
}
*Cannot bind*
错误:
g++ -Wall -Wunused -Wuninitialized -Wextra -std=gnu++11 -g -g3 -std=gnu++11 -c -o test_iters.o test_iters.cpp
test_iters.cpp: In instantiation of ‘std::ostream& operator<<(std::ostream&, T) [with T = std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, char> >; <template-parameter-1-2> = std::pair<const std::basic_string<char>, char>; std::ostream = std::basic_ostream<char>]’:
test_iters.cpp:20:17: required from here
test_iters.cpp:31:8: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
os << *iterator; // Compilation error if uncommenting: Cannot bind
^
In file included from /usr/include/c++/4.8/iostream:39:0,
from test_iters.cpp:1:
/usr/include/c++/4.8/ostream:602:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::pair<const std::basic_string<char>, char>]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
make: *** [test_iters.o] Error 1
*Ambiguous override*
错误:
g++ -Wall -Wunused -Wuninitialized -Wextra -std=gnu++11 -g -g3 -std=gnu++11 -c -o test_iters.o test_iters.cpp
test_iters.cpp: In function ‘std::ostream& operator<<(std::ostream&, T)’:
test_iters.cpp:32:7: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘const char [8]’)
cout << "Testing" << endl; // Compilation error if uncommenting: Ambiguous overload for the first <<
^
test_iters.cpp:32:7: note: candidates are:
In file included from /usr/include/c++/4.8/iostream:39:0,
from test_iters.cpp:1:
/usr/include/c++/4.8/ostream:174:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(bool __n)
^
/usr/include/c++/4.8/ostream:245:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(const void* __p)
^
test_iters.cpp:28:10: note: std::ostream& operator<<(std::ostream&, T) [with T = const char*; <template-parameter-1-2> = char; std::ostream = std::basic_ostream<char>]
ostream& operator<<(ostream& os, T iterator)
^
...
旧代码(仅用于文档目的):
#include <iostream>
#include <map>
#include <list>
#include <string>
using namespace std;
typedef pair<string, char> pair_t;
typedef map<pair_t::first_type, pair_t::second_type> map_t;
typedef pair<map_t::iterator, bool> retval_insert_t;
// ***** pair
// Templated form of overloading << for a pair
template<typename first_class, class second_class>
ostream& operator<<(ostream& os, const pair<first_class, second_class>& p);
// ***** iterator
// Templated form of overloading << for a const_iterator
template<class T>
ostream& operator<<(ostream& os, typename T::const_iterator it);
// Templated form of overloading << for an iterator ... does not work
template<class T>
ostream& operator<<(ostream& os, typename T::iterator it);
// Explicit form of overloading << for an iterator
ostream& operator<<(ostream& os, map_t::iterator it); // Compile error if commenting this line
// ***** return value of insert (a map)
// Explicit form of overloading << for the return value of insert
ostream& operator<<(ostream& os, const retval_insert_t& retval);
int main(void) {
pair_t p2;
p2 = make_pair(string("Fer"), 'C');
map_t grade_list;
retval_insert_t retval = grade_list.insert(p2);
cout << retval.first << endl; // Does not work with a templated operator<<
return 0;
}
//********************** Overloaded << functions ***************************************
//************************ Explicit and templated ****************************************
// ***** pair
// Templated form of overloading << for a pair
template<class first_class, class second_class>
ostream& operator<<(ostream& os, const pair<first_class, second_class>& p)
{
os << "(" << p.first << ", " << p.second << ")";
return os;
}
// ***** iterator
// Templated form of overloading << for a const_iterator
template<class T>
ostream& operator<<(ostream& os, typename T::const_iterator it)
{
os << *it;
return os;
}
// Templated form of overloading << for an iterator ... does not work
template<class T>
ostream& operator<<(ostream& os, typename T::iterator it)
{
os << *it;
return os;
}
// Explicit form of overloading << for an iterator
ostream& operator<<(ostream& os, map_t::iterator it)
{
os << *it;
return os;
}
// ***** return value of insert (a map)
// Explicit form of overloading << for the return value of insert
ostream& operator<<(ostream& os, const retval_insert_t& retval)
{
os << "retval : <" << retval.first << ", " << retval.second << ">";
return os;
}
答案 0 :(得分:1)
T
中的typename T::iterator
是一个非推导的上下文,因此当您尝试调用T
时,编译器无法确定operator<<
应该是什么迭代器类型。
编写适用于迭代器的重载的一种方法是使用SFINAE来检测给定类型是否为迭代器:
template <class T, class = typename std::iterator_traits<T>::value_type>
std::ostream& operator<<(std::ostream& os, T iterator);
// ^ This T can be deduced