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

发布于 2024-10-15 07:47:44 字数 756 浏览 1 评论 0原文

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

I'm curious if there's any way to do this in C++. Let's say I have a templated vector class:

template <typename T>
class vector {          
public:
      vector(T a, T b, T c) : x(a), y(b), z(c) {}

      T x,y,z;
};

And then I have a templated addition operator:

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); 
}

I'm curious if it's possible to modify that operator so the result is whichever of the two types A and B is more precise, aside from manually specializing it.

For example:

vector<float>       + vector<double> would produce a vector<double>, 
vector<long double> + vector<float>  would produce a vector<long double>

My guess would be that there's no automatic support for this in C++, but I thought I'd ask.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

残月升风 2024-10-22 07:47:44

没有任何库形式的内置支持,但您可以使用条件 (?:) 运算符来完成此操作。

在回复另一个答案时,Johannes Schaub 发布了 a promote 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);  
} 

There isn't any built-in support in the form of a library, but you can accomplish this using the conditional (?:) operator.

In reply to another answer, Johannes Schaub posted a promote<T, U> template that wraps the logic up quite nicely. With the template, you should be able to write:

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);  
} 
耀眼的星火 2024-10-22 07:47:44

在 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 在他的回答

in C++0x, you could say:

template <typename A, typename B> 
auto operator +(const vector<A> &a, const vector<B> &b) -> vector<decltype(a.x + b.x)>
{
    //...
}

In C++03, you need to define all the combinations yourself, although you can do it in a reusable op_traits scheme that can be applied to a variety of different operators. James McNellis provides some details on this in his answer

暗藏城府 2024-10-22 07:47:44

Andrei Alexandrescu 在他 2001 年 4 月 1 日的 DDJ 文章 通用:最小和最大 Redivivus

总之,总体问题非常复杂。

Andrei 使用了 80 行支持代码,这些代码又依赖于 Loki 库。

干杯&哈,.

Andrei Alexandrescu discussed this in his 1st April 2001 DDJ article Generic: Min and Max Redivivus.

In short, the general problem is very complex.

Andrei used 80 lines of support code, those lines in turn relying on the Loki library.

Cheers & hth,.

狂之美人 2024-10-22 07:47:44

有一种相对简单的方法可以使用模板专业化来做到这一点

 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到适当的类型。但我希望你明白

There is a relatively easy way to do this with template specializations

 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;

Then you use this to create a 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;

I'm not sure how to compare these to get a typedef in the specialization to the appropiate type though. But i hope you get the idea

起风了 2024-10-22 07:47:44

模式“类型选择”(在“现代 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); 
}

Pattern "Type Selection" (read about it in "Modern C++ Design") can be useful here.

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); 
}
御守 2024-10-22 07:47:44

我选择尺寸更大的类型:

帮助模板:

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

I'm choosing the type greater in size:

Helper templates:

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;
};

Now use it:

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); 
}

See online demonstration : http://www.ideone.com/PGyA8

(り薆情海 2024-10-22 07:47:44

您可以通过使用函数重载来实现您的目标。这意味着除了通用之外:

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); 
}

您的另一个选择是在向量模板上实现所需类型的转换运算符。让浮点向量能够通过运算符返回双精度向量。

You can accomplish your goal somewhat by using function overloading. Meaning that in addition to the generic:

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); 
}

you also declare overloads for specific types, and these then get used rather than generically manufactured ones:

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); 
}

Your other option would be to implement conversion operators on your vector template for the types required. Have a float vector be able to return a double vector via an operator.

開玄 2024-10-22 07:47:44

是的。这是 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 方法来实现。

Yep. Here's the C++03 method:

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&)
{
  // ...
}

Obviously you do it the C++0x way if you can.

私野 2024-10-22 07:47:44

C++11 引入了 std::common_type ,并且 C++14 引入了 std::common_type_t 因此您现在应该能够编写:

template <typename A, typename B> 
vector<std::common_type_t<A,B>::type> operator+(const vector<A> &a, const vector<B> &b) { 
   return vector<std::common_type_t<A,B>::type>(a.x+b.x, a.y+b.y, a.z+b.z); 
}

C++11 introduced std::common_type, and C++14 introduced std::common_type_t so you should now be able to write:

template <typename A, typename B> 
vector<std::common_type_t<A,B>::type> operator+(const vector<A> &a, const vector<B> &b) { 
   return vector<std::common_type_t<A,B>::type>(a.x+b.x, a.y+b.y, a.z+b.z); 
}
樱花坊 2024-10-22 07:47:44

你永远无法完成这个:

vector; + 矢量<双>会产生一个向量

而无需大量欺骗或返回指向您自己设计的某些小玩意的指针,因为operator+必须返回编译时已知的类型。您要求返回在运行时确定的类型。

You'll never be able to accomplish this:

vector<float> + vector<double> would produce a vector<double>

without massive trickery or returning a pointer to some gizmo of your own design because operator+ must return a type that is known at compile-time. You are asking to return a type that is determined at run-time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文