2017-11-17 2 views
2

표현 템플릿을 사용할 때 전문화는 어떻게 작성합니까? 내가 VecExpression<Vector>를 확장하는 Vector 클래스와 [] 연산자와 루프를 사용하는 VecExpression 클래스의 생성자가있는 경우, 위키 백과에 따르면특정 유형에 대해 expression-templates를 사용하는 방법은 무엇입니까?

template <typename E1, typename E2> 
class VecSum : public VecExpression<VecSum<E1, E2> > { 
    E1 const& _u; 
    E2 const& _v; 
public: 
    VecSum(E1 const& u, E2 const& v) : _u(u), _v(v) { 
     assert(u.size() == v.size()); 
    } 
    double operator[](size_t i) const { return _u[i] + _v[i]; } 
    size_t size()    const { return _v.size(); } 
}; 

template <typename E1, typename E2> 
VecSum<E1,E2> const 
operator+(E1 const& u, E2 const& v) { 
    return VecSum<E1, E2>(u, v); 
} 

다음 Wikipedia example에서, 나는 벡터의 합 템플릿 클래스과 같이 할 수 있습니다 이 작품 왜

Vector a = ...; 
Vector b = ...; 
Vector c = ...; 
Vector d = a+b+c; 

내가 얻을,하지만 난 스칼라로 확장하는 방법을 잘 모르겠어요 :이 루프 그래서 다음과 같은 경우에만 사용 단일 루프와 같은 문을 병합 수 있습니다. 전체 벡터에 스칼라 (int, float 또는 double)를 추가 할 수 있기를 원하지만이 작업을 수행하는 방법을 모르겠습니다. 다른 해결책이있다,

template<typename E2> VecSum<int, E2>{ /*stuff goes here*/ } 
template<typename E1> VecSum<E1, int>{ /*stuff goes here*/ } 
template<typename E2> VecSum<float, E2>{ /*stuff goes here*/ } 
template<typename E1> VecSum<E1, float>{ /*stuff goes here*/ } 
template<typename E2> VecSum<double, E2>{ /*stuff goes here*/ } 
template<typename E1> VecSum<E1, double>{ /*stuff goes here*/ } 

을하지만이 필요한 것보다 그것의 더 많은 작품처럼 보인다 : 내 추측은 같은 VecSum 클래스에 대한 전문화를 만드는 것입니다?

+0

'int + E2'는 무엇을 의미합니까? 그 연산자는 무엇이라고 생각합니까? –

+0

@PasserBy 나는 그것에 대해 아주 분명하지 않았습니다. 각각의 VecSum 전문화에서,'operator []'코드에서, 나는 단지'_u + _v [i]'와 같은 것을 할 것이고, 단지 비 스칼라에'[]'만을 사용할 것입니다. – BadProgrammer99

답변

2

SFINAE를 사용하여 유형이 arithmethic이고 필요에 따라 전문화되어 있는지 확인하기 만하면됩니다.

예 :

template <typename E1, typename E2, typename Enable = void > class VecSum; 

template <typename E1, typename E2> 
class VecSum< E1, E2, 
     typename std::enable_if_t<!std::is_arithmetic<E1>::value && !std::is_arithmetic<E2>::value> 
     > : public VecExpression<VecSum<E1, E2> > 
{ 
    E1 const& _u; 
    E2 const& _v; 

    public: 

    VecSum(E1 const& u, E2 const& v) : _u(u), _v(v) 
    { 
     assert(u.size() == v.size()); 
    } 

    double operator[](size_t i) const { return _u[i] + _v[i]; } 
    size_t size()    const { return _v.size(); } 
}; 

template <typename E1, typename E2> 
class VecSum < E1, E2, 
     typename std::enable_if_t< std::is_arithmetic<E1>::value && !std::is_arithmetic<E2>::value> 
     > : public VecExpression<VecSum<E1, E2> > 
{ 
    E1 const& _u; 
    E2 const& _v; 

    public: 

    VecSum(E1 const& u, E2 const& v) : _u(u), _v(v) 
    { 
    } 

    double operator[](size_t i) const { return _u + _v[i]; } 
    size_t size()    const { return _v.size(); } 
}; 


template <typename E1, typename E2> 
class VecSum < E1, E2, 
     typename std::enable_if_t< !std::is_arithmetic<E1>::value && std::is_arithmetic<E2>::value> 
     > : public VecExpression<VecSum<E1, E2> > 
{ 
    E1 const& _u; 
    E2 const& _v; 

    public: 

    VecSum(E1 const& u, E2 const& v) : _u(u), _v(v) 
    { 
    } 

    double operator[](size_t i) const { return _u[i] + _v; } 
    size_t size()    const { return _u.size(); } 
}; 

int main(){ 
    Vec v0 = { 1, 2, 3 ,4 }; 
    Vec v1 = {10, 20,30,40 }; 
    Vec v2 = {100,200,300,400 }; 

    { 

     Vec sum = v0+v1+v2; 
     Vec v3(4); 

     for(int i=0;i<4;++i) 
      v3[i]=sum[i]; 


     for(unsigned int i=0;i<v3.size();++i) 
      std::cout << v3[i] << std::endl; 
    } 

    std::cout << "with lhs skalar" << std::endl; 

    { 
     Vec sum = 5 + 50 + v1; 
     Vec v3(4); 

     for(int i=0;i<4;++i) 
      v3[i]=sum[i]; 


     for(unsigned int i=0;i<v3.size();++i) 
      std::cout << v3[i] << std::endl; 

    } 

    std::cout << "with rhs skalar" << std::endl; 

    { 
     Vec sum = v1 + 5 + 50 ; 
     Vec v3(4); 

     for(int i=0;i<4;++i) 
      v3[i]=sum[i]; 


     for(unsigned int i=0;i<v3.size();++i) 
      std::cout << v3[i] << std::endl; 

    } 

} 
1

어떤 대안에 대해 :

또한 VecExpression::size을 변경해야합니다
class AnySize { }; 
bool operator==(AnySize, AnySize) { return true; } 
bool operator==(size_t, AnySize) { return true; } 
bool operator==(AnySize, size_t) { return true; } 

template <typename T> 
class Scalar { 
    T _value; 

public: 
    explicit Scalar(T value) : _value(value) {} 
    T operator[](int) { return _value; } 
    AnySize size() { return {}; } 
} 

은 적절한 크기를 제공하기보다는 항상보다 왼쪽의

AnySize size_for(AnySize, AnySize) { return {}; } 
size_t size_for(size_t lhs, AnySize) { return lhs; } 
size_t size_for(AnySize, size_t rhs) { return rhs; } 
size_t size_for(size_t lhs, size_t rhs) { return lhs; } 

auto VecExpression<E1,E2>::size() { return size_for(_u.size(), _v.size()); } 
+0

이것이 작동하는 동안 플래그 값 (-1과 같은)을 반환 한 Scalar 클래스에 size 함수를 추가하는 것이 더 좋을 수 있으므로 if 문을 추가하여 VecSum의 생성자에서 확인하십시오. 이 방법은 다른 크기의 벡터를 추가하려고하면 여전히 오류 검사를 유지할 수 있습니다. – BadProgrammer99

+0

@ BadProgrammer99 마커 값보다는 마커 유형을 선호합니다. 또한'std :: size_t'는 부호가 없으므로 -1은 큰 값이됩니다. – Caleth