我有一个带有重载+运算符的模板类。当我添加两个或两个双打时,这工作正常。如何将它添加到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;
}
我希望能够做到这一点
std::cout << doubleTt1 + intTt2 << /n;
答案 0 :(得分:13)
这里有龙。你正在进入c ++的部分内容,这可能会导致很多问题发布到StackOverflow :)如果你真的想这样做,请仔细思考。
从简单部分开始,您希望允许operator+
添加与T
并不总是相同的类型。从这开始:
template <typename T2>
TemplateTest<T> operator+(const TemplateTest<T2>& rhs) {
return TemplateTest<T>(this->x + rhs.x);
}
请注意,这是T2
以及T
的模板。添加doubleTt1 + intTt2
时,T
将为doubleTt1
,T2
将为intTt2
。
但这是整个方法的大问题。
现在,当您添加double
和int
时,您期望什么? 4 + 2.3 = 6.3
?还是4 + 2.3 = 6
?谁会期待6
?您的用户应该,因为您将双重投回到int
,从而丢失了小数部分。有时。取决于首先是哪个操作数。如果用户写了2.3 + 4
,他们会得到(正如预期的那样?)6.3
。困扰的图书馆使悲伤的用户。如何最好地处理?我不知道......
答案 1 :(得分:13)
使用名为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);
}
调用为:
std::cout << Add<double>(intTt1, doubleTt1) << std::endl;
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);
}
这将确保执行通常的算术转换(整数提升,转换为浮点等)并最终得到预期的结果类型。
您的C ++实现可能已经支持这些C ++ 0x功能;你想查阅你正在使用的任何编译器的文档。
答案 2 :(得分:5)
我希望能够做到这一点
std :: cout&lt;&lt; doubleTt1 + intTt2&lt;&lt; “\ n” 个;
此案例可能需要的是类型特征。基本上,这些是包含typedef
s的模板类。然后,部分专门化这样的模板以覆盖typedef
s。
(这可能有点天真,但它应该得到基本的想法。)
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!
};
现在你部分专门针对A
和B
的各种组合使用
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
};
现在你可以编写一个相当通用的添加操作,如下所示:
template <typename A, typename B>
typename add_traits<A,B>::sum_t add(A first_summand, B second_summand)
{
// ...
}
如您所见,您没有指定具体的返回类型;相反,您让编译器通过add_traits
模板类来计算它。一旦编译器为特定的add
函数生成代码,它将在相应的add_traits
类中查找类型,并且由于您提供的部分专用版本,您可以确保应用某些类型的“组合”。
P.S。:同样的技术会例如当你想减去无符号数时也很有用。从另一个中减去一个unsigned int
会导致否定答案;结果类型必须是(signed
)int
。
P.P.S。:根据以下评论进行更正。
答案 3 :(得分:3)
add运算符通常应该是一个自由函数,以避免更喜欢任何操作数类型,如@Stephen很好地解释。这样它就完全对称了。假设你有一个返回存储值的函数get
,这可能如下所示(或者,如果这样的get
函数不存在,你可以将它声明为朋友)
template<typename T1, typename T2>
TemplateTest<???> operator+(const TemplateTest<T1>& t1, const TemplateTest<T2>& t2)
{
return TemplateTest<???>(t1.get() + t2.get());
}
现在的问题是找到一个结果类型。正如其他答案所示,这可以在C ++ 0x中使用decltype
。您还可以使用?:
运算符的规则来模拟这一点,这些规则大多非常直观。 promote<>是使用该技术的模板
template<typename T1, typename T2>
TemplateTest< typename promote<T1, T2>::type >
operator+(const TemplateTest<T1>& t1, const TemplateTest<T2>& t2)
{
return TemplateTest< typename promote<T1, T2>::type >(t1.get() + t2.get());
}
现在,例如,如果您添加double
和int
,则会产生double
作为结果。或者,如promote<>
答案中所示,您还可以对promote
进行专门化,以便将其直接应用于TemplateTest
类型。
答案 4 :(得分:2)
如果这主要是针对基本类型,那么在新标准出现之前,您可以帮助自己使用元函数。
template<typename T1,
typename T2,
bool T1_is_int = std::numeric_limits<T1>::is_integer,
bool T2_is_int = std::numeric_limits<T2>::is_integer,
bool T1_is_wider_than_T2 = (sizeof(T1) > sizeof(T2)) > struct map_type;
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, true > { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, false> { typedef T2 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, false, true , b> { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, true , false, b> { typedef T2 type; };
template<typename T, typename U>
typename map_type<TemplateTestT<T>, TemplateTest<U> >::type
operator+(TemplateTest<T> const &t, TemplateTest<U> const &u) {
return typename map_type<TemplateTest<T>, TemplateTest<U> >::type(x + t1.x);
}
当然,这最好与char_traits理念相结合:
template <typename A, typename B>
struct add_traits
{
typedef A first_summand_t;
typedef B second_summand_t;
typedef typename map_type<A, B>::type sum_t;
};
这样你仍然可以专注于没有numeric_limits重载的类型。
哦,在生产代码中,你可能想要正确地命名它并在整数类型中添加有符号/无符号不匹配的东西。
答案 5 :(得分:2)
获取支持新C ++ 0x decltype运算符的编译器。
template < typename T1, typename T2 >
auto add(T1 t1, T2 t2) -> decltype(t1+t2)
{
return t1 + t2;
}
现在你不必放弃那些“特质”类。
答案 6 :(得分:1)
您可以使用模板添加int和double值。在函数中,指定2个参数,并且在向函数传递值时,在尖括号中指定其类型。
示例:
//template
template<typename T1, typename T2>
void add(T1 a, T2 b)
{
//for adding values
cout<<"\n\nSum : "<<a+b;
}
int main ()
{
//specify types while passing values to funcion
add<int,double>(4,5.5454);
add<float,int>(4.7,5);
add<string,string>("hi","bye");
return 0;
}
答案 7 :(得分:0)
通过为TemplateTest<double>
:
operator TemplateTest<double>() {
return TemplateTest<double>((double)x);
}
实际上这可能不是一个好主意,因为x
不一定能安全地转换为双倍;碰巧你在这里使用了TemplateTest<int>
,但之后可能会使用TemplateTest<std::string>
。你应该重新考虑你正在做的事情,并决定你是否确实需要这种行为
答案 8 :(得分:0)
旧问题的新答案。
对于C ++ 0x,您可以使用decltype
,因为其他答案已经讨论过了。
我认为common_type
比decltype
更适合这种情况。
以下是通用添加中使用的common_type
的示例:
#include <iostream>
#include <array>
#include <type_traits>
using namespace std;
template <typename T, typename U, unsigned long N>
array<typename common_type<T, U>::type, N> // <- Gets the arithmetic promotion
add_arrays(array<T, N> u, array<U, N> v)
{
array<typename common_type<T, U>::type, N> result; // <- Used again here
for (unsigned long i = 0; i != N; ++i)
{
result[i] = u[i] + v[i];
}
return result;
}
int main()
{
auto result = add_arrays( array<int, 4> {1, 2, 3, 4},
array<double, 4> {1.0, 4.23, 8.99, 55.31} );
for (size_t i = 0; i != 4; ++i)
{
cout << result[i] << endl;
}
return 0;
}
它基本上返回不同算术运算将提升的值。关于它的一个好处是它可以采用任意数量的模板args。注意:不要忘记在其末尾添加::type
。这就是得到你想要的实际类型结果。
对于那些仍在使用pre-c ++ 11的人来说,还有一个common_type
的提升版本