如何对特定类型使用表达式模板?
How to use expression-templates for specific types?
使用表达式模板时,如何创建专业化?从 Wikipedia example,我可以像这样制作向量和模板 class:
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);
}
根据维基百科,如果我有一个扩展 VecExpression<Vector>
的 Vector
class 和一个使用 VecExpression
class 的构造函数16=] 运算符和一个循环,这将允许循环合并,所以像下面这样的语句只使用一个循环:
Vector a = ...;
Vector b = ...;
Vector c = ...;
Vector d = a+b+c;
我明白为什么会这样,但我不确定如何将其扩展到标量。我希望能够向整个 Vector 添加标量(int、float 或 double),但我不确定如何执行此操作。我最好的猜测是为 VecSum class 创建专业化,例如:
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*/ }
但这似乎比必要的工作多了很多,还有其他解决方案吗?
只需使用 SFINAE 检查类型是否为算术类型,并根据需要进行特化。
示例:
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;
}
}
替代方案如何:
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 {}; }
}
您还需要更改 VecExpression::size
,以提供合适的尺寸而不是总是左侧的
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()); }
使用表达式模板时,如何创建专业化?从 Wikipedia example,我可以像这样制作向量和模板 class:
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);
}
根据维基百科,如果我有一个扩展 VecExpression<Vector>
的 Vector
class 和一个使用 VecExpression
class 的构造函数16=] 运算符和一个循环,这将允许循环合并,所以像下面这样的语句只使用一个循环:
Vector a = ...;
Vector b = ...;
Vector c = ...;
Vector d = a+b+c;
我明白为什么会这样,但我不确定如何将其扩展到标量。我希望能够向整个 Vector 添加标量(int、float 或 double),但我不确定如何执行此操作。我最好的猜测是为 VecSum class 创建专业化,例如:
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*/ }
但这似乎比必要的工作多了很多,还有其他解决方案吗?
只需使用 SFINAE 检查类型是否为算术类型,并根据需要进行特化。
示例:
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;
}
}
替代方案如何:
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 {}; }
}
您还需要更改 VecExpression::size
,以提供合适的尺寸而不是总是左侧的
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()); }