我很好奇是否有任何方法可以在C ++中执行此操作。假设我有一个模板化的矢量类:
template <typename T>
class vector {
public:
vector(T a, T b, T c) : x(a), y(b), z(c) {}
T x,y,z;
};
然后我有一个模板化的加法运算符:
template <typename A, typename B>
vector<A> operator +(const vector<A> &a, const vector<B> &b) {
return vector<A>(a.x+b.x, a.y+b.y, a.z+b.z);
}
我很好奇是否可以修改那个操作符,因此除了手动专门化之外,结果是两种类型A和B中哪一种更精确。
例如:
vector<float> + vector<double> would produce a vector<double>,
vector<long double> + vector<float> would produce a vector<long double>
我的猜测是C ++中没有自动支持,但我想我会问。
答案 0 :(得分:9)
库中没有任何内置支持,但您可以使用条件(?:
)运算符来完成此操作。
在回答另一个答案时,Johannes Schaub发布了a promote<T, U>
template,它很好地包含了逻辑。使用模板,您应该能够写:
template <typename A, typename B>
vector< typename promote<A, B>::type >
operator+(const vector<A> &a, const vector<B> &b)
{
return vector< typename promote<A, B>::type >(a.x+b.x, a.y+b.y, a.z+b.z);
}
答案 1 :(得分:7)
在C ++ 0x中,您可以说:
template <typename A, typename B>
auto operator +(const vector<A> &a, const vector<B> &b) -> vector<decltype(a.x + b.x)>
{
//...
}
在C ++ 03中,您需要自己定义所有组合,尽管您可以在可重用的op_traits
方案中执行此操作,该方案可应用于各种不同的运算符。 James McNellis provides some details on this in his answer
答案 2 :(得分:3)
Andrei Alexandrescu在2001年4月1日的DDJ文章Generic: Min and Max Redivivus中对此进行了讨论。
简而言之,一般问题非常复杂。
Andrei使用了80行支持代码,这些代码依赖于Loki库。
干杯&amp; HTH,
答案 3 :(得分:1)
使用模板专业化有一种相对简单的方法
template< typename A >
struct TypePrecision {
static const int precisionLevel;
};
template< typename A >
const int TypePrecision< A >::precisionLevel = 0;
template<>
struct TypePrecision< float > {
static const int precisionLevel;
};
template<>
struct TypePrecision< long float > {
static const int precisionLevel;
};
template<>
struct TypePrecision< double > {
static const int precisionLevel;
};
template<>
struct TypePrecision< long double > {
static const int precisionLevel;
};
template<>
const int TypePrecision< float >::precisionLevel = 1;
template<>
const int TypePrecision< long float >::precisionLevel = 2;
template<>
const int TypePrecision< double >::precisionLevel = 3;
template<>
const int TypePrecision< long double >::precisionLevel = 4;
然后使用它来创建HigherPrecisionType
template < typename A , typename B >
struct HigherPrecisionType
{
static const int APrecision;
static const int BPrecision;
};
template < typename A , typename B >
const int HigherPrecisionType< A, B >::APrecision= TypePrecision< A >::precisionLevel;
template < typename A , typename B >
const int HigherPrecisionType< A, B >::BPrecision= TypePrecision< B >::precisionLevel;
我不确定如何比较这些以获得适合类型的专业化中的typedef。但我希望你明白这个想法
答案 4 :(得分:1)
模式“类型选择”(在“现代C ++设计”中阅读)在这里很有用。
template <bool flag, typename T, typename U>
struct Select {
typedef T Result;
};
template <typename T, typename U>
struct Select<false, T, U> {
typedef U Result;
};
...
template <typename A, typename B>
vector<Select<sizeof(A) > sizeof(B), A, B>::Result> operator +(const vector<A> &a, const vector<B> &b) {
return vector<Select<sizeof(A) > sizeof(B), A, B>::Result>(a.x+b.x, a.y+b.y, a.z+b.z);
}
答案 5 :(得分:1)
我选择的尺寸更大:
助手模板:
template<bool b, typename A, typename B>
struct choose_if
{
typedef A type;
};
template<typename A, typename B>
struct choose_if<false, A, B>
{
typedef B type;
};
template<typename A, typename B>
struct greater
{
static const bool value = sizeof(A) > sizeof(B);
typedef vector<typename choose_if<value, A, B>::type> type;
};
现在使用它:
template <typename A, typename B>
typename greater<A, B>::type operator +(const vector<A> &a, const vector<B> &b)
{
typedef typename greater<A, B>::type type;
return type(a.x+b.x, a.y+b.y, a.z+b.z);
}
参见在线演示:http://www.ideone.com/PGyA8
答案 6 :(得分:0)
您可以通过使用函数重载来实现目标。这意味着除了通用:
template <typename A, typename B>
vector<A> operator +(const vector<A> &a, const vector<B> &b) {
return vector<A>(a.x+b.x, a.y+b.y, a.z+b.z);
}
你还要为特定类型声明重载,然后使用它们而不是通用制造的:
vector<double> operator +(const vector<float> &a, const vector<double> &b) {
return vector<double>(a.x+b.x, a.y+b.y, a.z+b.z);
}
您的另一个选择是在矢量模板上实现所需类型的转换运算符。让浮点向量能够通过运算符返回双向量。
答案 7 :(得分:0)
是的。这是C ++ 03方法:
template < typename T1, typename T2 >
struct which_return;
template < typename T >
struct which_return<T,T> { typedef std::vector<T> type; };
template < >
struct which_return<int,double> { typedef std::vector<double> type; };
template < >
struct which_return<double,int> : which_return<int,double> {};
// etc...
template < typename T1, typename T2 >
typename which_return<T1,T2>::type operator+ (std::vector<T1> const&, std::vector<T2> const&)
{
// ...
}
如果可以的话,显然你是用C ++ 0x的方式做的。
答案 8 :(得分:-1)
你永远无法做到这一点:
vector<float> + vector<double> would produce a vector<double>
没有大量欺骗或返回指向您自己设计的某个Gizmo的指针,因为operator+
必须返回编译时已知的类型。您要求返回在运行时确定的类型。