0

我有许多向量类,我想为其实现一个通用流运算符,如下所示:

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];
};
4

4 回答 4

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 );
}
于 2013-04-03T15:55:42.547 回答
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;

}
于 2013-04-03T16:13:29.563 回答
2

IIRC,您可以使用 SFINAE(如 Drew Dormann 的回答)或使用命名空间的参数相关名称查找:

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_ 的方法。

于 2013-04-03T16:33:18.733 回答
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定义T::num_elems可转换为的类型size_t,例如您的枚举。

此解决方案假定使用 C++11 编译器。

于 2013-04-03T16:30:06.210 回答