C++模板问题添加两种数据类型

Sar*_*ara 14 c++ templates

我有一个带有重载+运算符的模板类.当我添加两个或两个双打时,这工作正常.如何将它添加到int和double并返回double?

template <class T>
class TemplateTest
{
private:
  T x;

public:

  TemplateTest<T> operator+(const TemplateTest<T>& t1)const
  {
    return TemplateTest<T>(x + t1.x);
  }
}

in my main function i have

void main()
{
  TemplateTest intTt1 = TemplateTest<int>(2);
  TemplateTest intTt2 = TemplateTest<int>(4);
  TemplateTest doubleTt1 = TemplateTest<double>(2.1d);
  TemplateTest doubleTt2 = TemplateTest<double>(2.5d);

  std::cout <<  intTt1 + intTt2 << /n;
  std::cout <<  doubleTt1 + doubleTt2 << /n;
}
Run Code Online (Sandbox Code Playgroud)

我希望能够做到这一点

std::cout <<  doubleTt1 + intTt2 << /n;
Run Code Online (Sandbox Code Playgroud)

Ste*_*hen 13

这里是龙.你正在进入c ++的部分内容,这可能会导致很多问题发布到StackOverflow :)如果你真的想这样做,那么想想很久很难.

从简单部分开始,您希望允许operator+添加并非总是相同的类型T.从这开始:

template <typename T2>
TemplateTest<T> operator+(const TemplateTest<T2>& rhs) {
  return TemplateTest<T>(this->x + rhs.x);
}
Run Code Online (Sandbox Code Playgroud)

请注意,这是模板上T2,以及T.当添加doubleTt1 + intTt2,TdoubleTt1T2intTt2.

但这是整个方法的大问题.

现在,当你添加一个double和一个int,你期望什么? 4 + 2.3 = 6.3?还是4 + 2.3 = 6?谁会指望6?你的用户应该,因为你将双重投射到一个int,因此失去了小数部分.有时.取决于首先是哪个操作数.如果用户写了2.3 + 4,他们会得到(如预期的那样?)6.3.困扰的图书馆使悲伤的用户.如何最好地处理?我不知道...

  • 一个明显的例子是`std :: complex <float> + double`,它应该返回一个`std :: complex <double>`. (2认同)

Jam*_*lis 13

斯蒂芬已经对你可能遇到的问题做了很好的解释.您可以为模板的所有实例化的所有可能组合定义重载(因此,您实际上已经为double + double,int + double,double + int等定义了运算符).这可能很快变得难以处理,并且难以跟踪支持哪些组合.

你可能最好使用一个名为的非成员函数Add().这样做的好处是您可以指定返回类型.缺点是您必须指定返回类型.:-)但是,一般情况下,这比自动执行意外转换更好.

template <typename R, typename T, typename U>
TemplateTest<R> Add(const TemplateTest<T>& t, const TemplateTest<U>& u)
{
    return TemplateTest<R>(t.x + u.x);
}
Run Code Online (Sandbox Code Playgroud)

调用为:

std::cout << Add<double>(intTt1, doubleTt1) << std::endl;
Run Code Online (Sandbox Code Playgroud)

C++ 0x将添加对许多语言功能的支持,这将使这更简单,并允许您编写合理的operator+重载:

template <typename T, typename U>
auto operator+(const TemplateTest<T>& t, const TemplateTest<U>& u) 
    -> TemplateTest<decltype(t.x + u.x)>
{
    return TemplateTest<decltype(t.x + u.x)>(t.x + u.x);
}
Run Code Online (Sandbox Code Playgroud)

这将确保执行通常的算术转换(整数提升,转换为浮点等),并最终得到预期的结果类型.

您的C++实现可能已经支持这些C++ 0x功能; 你想查阅你正在使用的任何编译器的文档.

  • decltype为+1.在C++ 0x中,您还可以省略正文中返回类型的重复.你可以说`return {tx + ux}`.让它看起来更干净:) (3认同)

sta*_*ica 5

我希望能够做到这一点

std :: cout << doubleTt1 + intTt2 <<"\n";

这种情况你可能需要的是类型特征.基本上,这些是包含typedefs的模板类.然后,您可以部分专门化这样的模板来覆盖typedefs.

基本示例:

(这可能有点天真,但它应该得到基本的想法.)

template <typename A, typename B>
struct add_traits
{
    typedef A first_summand_t;   // <-- (kind of an "identity type")
    typedef B second_summand_t;  // <-- (ditto; both aren't strictly necessary)
    typedef B sum_t;             // <-- this is the interesting one!
};
Run Code Online (Sandbox Code Playgroud)

现在你部分专门针对各种组合AB:

template<>
struct add_traits<int, int>
{
    typedef int first_summand_t;
    typedef int second_summand_t;
    typedef int sum_t;             // <-- overrides the general typedef
};

template<>
struct add_traits<int, double>
{
    typedef int first_summand_t;
    typedef double second_summand_t;
    typedef double sum_t;    // <-- overrides the general typedef
};

template<>
struct add_traits<double, int>
{
    typedef double first_summand_t;
    typedef int second_summand_t;
    typedef double sum_t;    // <-- overrides the general typedef
};
Run Code Online (Sandbox Code Playgroud)

现在你可以编写一个相当通用的添加操作,如下所示:

template <typename A, typename B>
typename add_traits<A,B>::sum_t add(A first_summand, B second_summand)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,您没有指定具体的返回类型; 相反,你让编译器通过add_traits模板类来计算它.一旦编译器为特定add函数生成代码,它将在相应的add_traits类中查找类型,并且由于您提供的部分专用版本,您可以确保将应用某些类型的"组合".


PS:当你想减去无符号数时,同样的技术也会很有用.一个unsigned int减去另一个可能导致一个否定的答案; 结果类型必须是(signed)int.


PPS:根据以下评论进行更正.