我有许多矢量类,我想要实现这样的通用流操作符:
template <typename T>
std::ostream& operator<<(std::ostream& os, const T& v)
{
for (int i = 0; i < T::num_elems; ++i)
{
os << " " << v.a[i];
}
return os;
}
这几乎可行,但我当然会收到os << " " << ...
的错误,因为它含糊不清。如何消除歧义并迫使<<
运算符在此处使用std::
?
或者,如何将此模板化流操作符的使用限制为仅仅我的矢量类?我把矢量类和流操作符放在一个单独的命名空间中,但这似乎还不够。
实际错误消息的开头:
foo.cpp:73: error: ambiguous overload for 'operator<<' in 'os << " "'
/usr/include/c++/4.2.1/ostream:169:0 /usr/include/c++/4.2.1/ostream:169: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>] <near match>
/usr/include/c++/4.2.1/ostream:177:0 /usr/include/c++/4.2.1/ostream:177: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>] <near match>
/usr/include/c++/4.2.1/ostream:185:0 /usr/include/c++/4.2.1/ostream:185: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
...
进一步澄清:流操作符仅用于测试工具(UnitTest ++),它不是公共API的一部分。矢量类也是小型自定义固定大小的矢量(实际上只是简单的数组),而不是C ++矢量。
我需要使用其中一个向量类的精简示例:
struct VectorClass {
enum { num_elems = 16 };
int32_t a[num_elems];
};
答案 0 :(得分:3)
大约有20个类似的类,具有不同的POD类型和数组大小,但在其他方面相同。
创建一个执行广义工作的命名函数。
template <typename T>
std::ostream& SendVectorToOstream(std::ostream& os, const T& v)
{
for (int i = 0; i < T::num_elems; ++i)
{
os << " " << v.a[i];
}
return os;
}
现在,您可以将operator<<
功能转发给它。
std::ostream& operator<<(std::ostream& os, const VectorClassA & v)
{
return SendVectorToOstream( os, v );
}
std::ostream& operator<<(std::ostream& os, const VectorClassB & v)
{
return SendVectorToOstream( os, v );
}
std::ostream& operator<<(std::ostream& os, const VectorClassC & v)
{
return SendVectorToOstream( os, v );
}
答案 1 :(得分:2)
我认为你看错了路。模板不是解决方案。你想要的是继承。像这样的东西
template< typename T>
struct VectorClass {
enum { num_elems = 4 };
T* a;
};
template< typename T>
std::ostream& operator<<(std::ostream& os, const VectorClass<T>& v)
{
for (int i = 0; i < VectorClass<T>::num_elems; ++i)
{
os << " " << v.a[i];
}
return os;
}
template< typename T>
class DerivedClass : public VectorClass<T> {
};
int main(){
DerivedClass<int> v;
int* tmp = new int[VectorClass<int>::num_elems];
for (int i = 0; i < VectorClass<int>::num_elems; ++i) {
tmp[i] = i;
}
v.a = tmp;
cout << v;
}
答案 2 :(得分:2)
namespace all_my_vectors
{
struct myVector1 { int a; };
struct myVector2 { int a; };
template < typename Vector >
std::ostream& operator<< (std::ostream& o, Vector const& v)
{
o << v.a; // look up name in std::ostream, namespace std, global namespace, namespace of v.a
return o;
}
}
int main()
{
all_my_vectors::myVector1 v1;
all_my_vectors::myVector2 v2;
std::cout << v1 << v2; // look up name in std::ostream, namespace std, global namespace, namespace all_my_vectors
return 0;
}
编辑:如果他们共享一个共同的基类,你应该使用stardust_的方法。
答案 3 :(得分:1)
如果您的所有矢量类都有公共属性,例如num_elems
,则可以使用SFINAE实现此功能。
template <typename T, size_t SFINAE = T::num_elems >
// The only difference is here ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
std::ostream& operator<<(std::ostream &os, const T& v)
{
for (int i = 0; i < T::num_elems; ++i)
{
os << " " << v.a[i];
}
return os;
}
此更改会强制此ostream <<
仅适用于定义T
的{{1}}类型,可以转换为T::num_elems
,就像您的枚举一样。
此解决方案假定使用C ++ 11编译器。