2015-01-10 2 views
1

저는 수학적 벡터 클래스를 만들고 있습니다.벡터 연산자와 형식 변환

그 운영 전환이 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) 
    //} 

, 나는 표준을 사용해야합니다 : common_type을 사용하여 올바른 유형을 찾으십시오. 불행하게도, 내가 얻을 같은 컴파일러 오류 : 그래서

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

:

  • 내가 정상적인 필요를 모두 수행하고, 표준 : 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 
    

    는 관련 코드 ?
  • std :: common_type을 사용하는 벡터 및 스칼라 버전이 간섭하는 것 같습니다. 이것을 막을 수 있습니까?
  • 어떻게하면됩니까?

감사합니다.

답변

1

구현에서 동일한 연산을 사용하는 경우 인스턴스화는 동일한 경고를 생성합니다.

당신은이 예제를 시도 할 수 있습니다

:

#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에 해당하는 경고가 존재하지 않습니다

+0

영감을주는 예제 추가 (** [live on coliru] (http://coliru.stacked-crooked.com/a/d4da3cc344ac86d9) **) – sehe

+0

감사합니다. 템플릿 매개 변수 목록에 std :: common_type이있는 것으로 보입니다. 여기에 내가 결국에 들어갔습니다 : http://coliru.stacked-crooked.com/a/b96c12724a2dc3fc – user673679

+0

@ user673679 예, 가능하다고 생각됩니다. 인수 목록이나 반환 형식에 넣으면 ** [SFINAE] (http://en.cppreference.com/w/cpp/language/sfinae) **가 가능합니다. 여기서 컴파일러는 대체가 발생할 수있는 오버로드를 자동으로 무시할 수 있습니다. 오류 _ 선언에 _. 귀하의 경우에는 다른 '연산자 *'오버로드가있는 경우 쉽게 발생할 수 있으며, 호출하면 SFINAE 때문에 스칼라 버전이 삭제됩니다. – sehe