矢量运算符和类型转换

vector operators and type conversions

我正在创建一个数学向量 class。

我希望它的运算符提供类型之间的转换/警告行为,类似于 C++ 中 POD 类型的转换方式,例如:

    //{
    //  auto f = 1.f;
    //  auto d = 2.0;

    //  f *= d; // warns about possible loss of data
    //  d *= f; // fine

    //  auto d2 = f * d; // fine (f promotion, d2 is double)
    //}

据我了解,我需要使用 std::common_type 来找到正确的类型。不幸的是,我收到如下编译器错误:

1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\type_traits(1446): error C2446: ':' : no conversion from 'Testing::Vector<float,3>' to 'float'
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>          TestVector.cpp(152) : see reference to class template instantiation 'std::common_type<float,Testing::Vector<float,3>>' being compiled

相关代码如下:

template<class ElementT, unsigned int Dimensions>
class Vector
{
public:

    typedef ElementT ElementT;
    static const unsigned int Dimensions = Dimensions;

    typedef std::array<ElementT, Dimensions> DataT;

    Vector():
        data() { }

    explicit Vector(std::initializer_list<ElementT> values):
        data()
    {
        std::copy(values.begin(), values.end(), data.begin());
    }

    template<class E>
    explicit Vector(Vector<E, Dimensions> const& other):
        data()
    {
        std::copy(other.Data().begin(), other.Data().end(), data.begin());
    }

    Vector& operator*=(ElementT value)
    {
        for (auto& e : data)
            e *= value;

        return *this;
    }

    Vector& operator*=(Vector const& other)
    {
        for (auto i = 0u; i != data.size(); ++i)
            data[i] *= other.data[i];

        return *this;
    }

    // etc. ...

    // Warnings are still propagated from the copy constructor
    // if this is used with inappropriate types...
    template<class E>
    operator Vector<E, Dimensions>() const
    {
        return Vector<E, Dimensions>(*this);
    }


    DataT& Data()
    {
        return data;
    }

    DataT const& Data() const
    {
        return data;
    }

private:

    friend std::ostream& operator<<(std::ostream& stream, Vector v)
    {
        for (auto const& e : v.data)
            stream << e << " ";

        return stream;
    }

    DataT data;
};

template<class E, unsigned int D>
Vector<E, D> operator*(Vector<E, D> const& v, E value)
{
    auto result = Vector<E, D>(v);
    result *= value;

    return result;
}

template<class E, unsigned int D>
Vector<E, D> operator*(Vector<E, D> const& v1, Vector<E, D> const& v2)
{
    auto result = Vector<E, D>(v1);
    result *= v2;

    return result;
}

template<class E, class T, unsigned int D>
Vector<std::common_type_t<E, T>, D> operator*(Vector<E, D> const& v, T value)
{
    auto result = Vector<std::common_type_t<E, T>, D>(v);
    result *= value;

    return result;
}

template<class E1, class E2, unsigned int D>
Vector<std::common_type_t<E1, E2>, D> operator*(Vector<E1, D> const& v1, Vector<E2, D> const& v2)
{
    auto result = Vector<std::common_type_t<E1, E2>, D>(v1);
    result *= v2;

    return result;
}

void TestVector()
{
    std::cout << "Testing Vector" << std::endl;

    using Vec3 = Vector<float, 3u>;

    // Same types. All fine.
    {
        auto v1 = Vec3({ 1, 2, 3 });
        auto v2 = Vec3({ 1, 2, 3 });

        v1 *= 2.f;
        v1 *= v2;

        std::cout << v1 << std::endl;
    }

    {
        auto v1 = Vec3({ 1, 2, 3 });
        auto v2 = Vec3({ 1, 2, 3 });

        std::cout << (v1 * 2.f) << std::endl;
        std::cout << (v1 * v2) << std::endl; // causes problems with std::common_type?
    }

    {
        auto v1 = Vector<float, 3u>({ 1, 2, 3 });
        auto v2 = Vector<double, 3u>({ 1, 2, 3 });

        v1 *= 2.0; // should probably produce a warning, but doesn't? :(
        v1 *= v2; // compiles with warning :)

        v2 *= v1;  // fine :)

        std::cout << v1 << std::endl;
    }

    {
        // The std::common_type versions seem to conflict?

        auto v1 = Vector<float, 3u>({ 1, 2, 3 });
        auto v2 = v1 * 2.0; // v1 promotion -> should create a Vector<double, 3u>
        auto v3 = v1 * v2; // v1 promotion -> should create another Vector<double, 3u> 

        std::cout << v2 << std::endl;
    }
}

所以:

谢谢。

如果您只是在实现中使用相同的操作,实例化将生成相同的警告。

你可以试试这个例子:

#include <type_traits>

template <typename T>
struct Vect3 {
    T a,b,c;

    template <typename U, typename V = typename std::common_type<T, U>::type>
        Vect3<V> operator*(U u) const { return  {a*u,b*u,c*u}; }

    template <typename U>
        Vect3& operator*=(U u) { a*=u; b*=u; c*=u; return *this; }
};

int main()
{
    auto f = Vect3<float>{1,2,3};
    auto d = 2.0;

    auto common = f * d; // fine!
    f *= d; // warns about possible loss of data in the instantion of operator*=
}

GCC 即使使用 -std=c++11 -Wall -pedantic -Wextra -Wconversion -Wconversion-extra 也不会发出警告,但对于您的原始示例也不会发出警告,所以我猜 GCC

中没有相应的警告