C ++从函数返回更精确的两个模板参数?

时间:2011-02-01 18:49:04

标签: c++ templates

我很好奇是否有任何方法可以在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 ++中没有自动支持,但我想我会问。

9 个答案:

答案 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+必须返回编译时已知的类型。您要求返回在运行时确定的类型。