我有一个简单的generice算术向量类,并希望为标量乘法实现*运算符:
template<class Value_T, unsigned int N>
class VectorT
{
public:
typedef Value_T value_type;
typedef unsigned int size_type;
size_type GetNumElements() const { return N; }
// class member
// elements in the vector
value_type elements[N];
// the number of elements
static const size_type size = N;
};
// scalar multiplication
template<class Value_T, unsigned int N>
const VectorT<Value_T, N> operator*(const VectorT<Value_T, N>& v, Value_T s)
{
VectorT<Value_T,N> vTemp(v);
for (unsigned int i = 0; i < v.GetNumElements(); i++)
{
vTemp.elements[i] *= s;
}
return vTemp;
}
像这样用它......
typedef VectorT<double, 3> Vec3;
int main(int argc, char* argv[])
{
Vec3 v;
Vec3 v2 = v * 2; // multiply with scalar int
return 0;
}
...给编译器错误C2782(MSVC2012)*运算符的模板参数Value_T是不明确的:int或double .
如果我在我的类中将*运算符定义为友元函数,则错误消失,并且对于标量int或double工作正常 . 但实际上这里不需要朋友声明,因为VectorT类的公共接口对于运营商来说已经足够了(在我的实际代码中我有成员privat和一些公共访问器方法) .
我希望标量乘法仅适用于Value_T类型:对于VectorT <int,N>我想只给整数值赋予运算符 . 我还希望运算符是commutativ . 这就是为什么我不将它实现为一个简单的成员函数,其中左手操作符始终是VectorT类型 .
如何在这里实现*运营商作为非会员和非朋友?
3 回答
到目前为止发布的答案建议为函数参数
s
的类型提供独立的模板参数 . 这是一种可行的方法,但不是唯一的方法 .或者,更好的解决方案可能是通过有意地将其放入非推导的上下文中,从模板参数推导过程中排除第二个参数 .
这样编译器将从
v
参数的类型推导出模板参数,但不会从s
参数的类型推断出 .s
仍然会有正确的类型,就像你想要的那样 .上面的方法利用了这样一个事实,即您的类模板已经提供了一个方便的内部类型名称
value_type
. 在更一般的情况下,可以通过使用identity
模板来实现相同的目的C标准库决定不包含
std::identity
模板,因为它的功能显然由std::decay
和std::remove_reference
覆盖 . 因此,通过使用标准模板,您可以实现通用解决方案以下文章提到了这个具体问题http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3766.html
看看运营商的定义
并在线
使用VectorT和int类型的参数调用operator * . 所以Value_T是一次加倍,另一次是另一次 . 您可以乘以2.0来解决歧义或将第三个模板参数添加到operator *定义:
首先,您可以使用
std::array
而不是实现VectorT
. 然而,您遇到的问题是由于表达式Vec3 v2 = v * 2;
中的积分文字2
的类型为int
. 因此,编译器无法推导出您的重载operator*
,因为它实现时仅适用于VectorT
包含与乘数相同类型的元素的情况 .为了克服这个问题,您可以为重载的
operator*
添加一个额外的模板参数,如下例所示:LIVE DEMO