如何强制 operator>>(C<T>) 重载以匹配容器?
How to force operator>>(C<T>) overload to match container?
我想要 operator>>()
重载任何 "base" 类型和任何容器类型。这是我目前所拥有的:
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 编译的容器类型模板(无需专门针对每个容器类型)?
您编写的 operator>>
重载适用于具有单个模板参数 (T
) 的模板模板 class (C
)。但是,std::vector
声明为:
template<
class T,
class Allocator = std::allocator<T>
> class vector;
第二个模板参数可能是默认的,但它仍然存在。因此,std::vector<uint32_t>
无法匹配 C<T>
- 因此唯一可行的重载是您编写的通用函数模板,它不会编译,因为您无法将 std::uintmax_t
分配给 vector
.
为了让您的函数接受 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
:
的 typedef
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;
};
并将其粘贴在 return 类型上:
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
),这样它们才不会模棱两可。
我想要 operator>>()
重载任何 "base" 类型和任何容器类型。这是我目前所拥有的:
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 编译的容器类型模板(无需专门针对每个容器类型)?
您编写的 operator>>
重载适用于具有单个模板参数 (T
) 的模板模板 class (C
)。但是,std::vector
声明为:
template<
class T,
class Allocator = std::allocator<T>
> class vector;
第二个模板参数可能是默认的,但它仍然存在。因此,std::vector<uint32_t>
无法匹配 C<T>
- 因此唯一可行的重载是您编写的通用函数模板,它不会编译,因为您无法将 std::uintmax_t
分配给 vector
.
为了让您的函数接受 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;
};
并将其粘贴在 return 类型上:
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
),这样它们才不会模棱两可。