C ++算术升级头的使用
我一直在玩弄一套模板来确定在C ++中给出两种基本types的正确提升types。 这个想法是,如果你定义一个自定义的数字模板,你可以使用这些来确定基于传递给模板的类的运算符+函数的返回types。 例如:
// Custom numeric class template <class T> struct Complex { Complex(T real, T imag) : r(real), i(imag) {} T r, i; // Other implementation stuff }; // Generic arithmetic promotion template template <class T, class U> struct ArithmeticPromotion { typedef typename X type; // I realize this is incorrect, but the point is it would // figure out what X would be via trait testing, etc }; // Specialization of arithmetic promotion template template <> class ArithmeticPromotion<long long, unsigned long> { typedef typename unsigned long long type; } // Arithmetic promotion template actually being used template <class T, class U> Complex<typename ArithmeticPromotion<T, U>::type> operator+ (Complex<T>& lhs, Complex<U>& rhs) { return Complex<typename ArithmeticPromotion<T, U>::type>(lhs.r + rhs.r, lhs.i + rhs.i); }
如果使用这些升级模板,则可以或多或less地将用户定义的types视为具有相同促销规则的原语。 所以,我想我的问题是这可能是有用的东西? 如果是这样的话,你想要什么样的常见任务,以便于使用的模板? 我正在做这样一个假设,即仅仅拥有促销模板将不足以实际采用。
顺便提一下,Boost在math/工具/升级头文件中有类似的地方,但是它更像是将值传递给标准的Cmath函数(期望2个或2个double)并绕过所有的整型。 是完全控制你的对象如何被转换的简单的东西?
TL; DR:除了促销本身的机制之外,您期望在算术推广标题中find哪种辅助模板?
这绝对是有用的 – 我们在math库中使用这些types的东西,正确地在expression式中input中间值。 例如,您可能有一个模板化的加法运算符:
template<typename Atype, typename Btype> type_promote<Atype, Btype>::type operator+(Atype A, Btype B);
这样,你可以编写一个generics操作符来处理不同的参数types,并且它会返回一个适当types的值,以避免在expression式中出现精度损失。对于正确的操作也是有用的在这些运算符中声明内部variables。
至于应该怎么处理这个问题:我只是在我们定义它们的源代码中进行了检查,我们在那里只是简单的ArithmeticPromotion声明 – 三个通用版本来解决复杂复杂的复杂真实复杂的变体,使用特定的真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真实真 我们没有任何其他的帮手模板,它不(从我们的使用)看起来像有任何我们会使用的自然模板。
(FWIW,如果你不想自己写这个,从http://www.codesourcery.com/vsiplplusplus/2.2/download.html下载我们的源代码,然后取出;src/vsip/core/promote.hpp
。即使在我们BSD许可的库中,虽然在文件本身中并没有这样说)。
为此,你可以使用?:
操作符。 它会给你两种types之间的共同types。 首先,如果两种types是相同的,那么你很好。 然后,如果types不同,则调用?:
并查看返回的types。
因为适用于两个不同types的操作数,所以需要特别说明非升级typeschar
, short
和它们的无符号/有符号的版本,结果将不是它们。 您还需要注意两个类可以转换为提升的算术types的情况。 为了得到正确的结果,我们检查?:
的结果是否是推广算术types(按照第13.6
的精神),然后使用该types。
// typedef eiher to A or B, depending on what integer is passed template<int, typename A, typename B> struct cond; #define CCASE(N, typed) \ template<typename A, typename B> \ struct cond<N, A, B> { \ typedef typed type; \ } CCASE(1, A); CCASE(2, B); CCASE(3, int); CCASE(4, unsigned int); CCASE(5, long); CCASE(6, unsigned long); CCASE(7, float); CCASE(8, double); CCASE(9, long double); #undef CCASE // for a better syntax... template<typename T> struct identity { typedef T type; }; // different type => figure out common type template<typename A, typename B> struct promote { private: static A a; static B b; // in case A or B is a promoted arithmetic type, the template // will make it less preferred than the nontemplates below template<typename T> static identity<char[1]>::type &check(A, T); template<typename T> static identity<char[2]>::type &check(B, T); // "promoted arithmetic types" static identity<char[3]>::type &check(int, int); static identity<char[4]>::type &check(unsigned int, int); static identity<char[5]>::type &check(long, int); static identity<char[6]>::type &check(unsigned long, int); static identity<char[7]>::type &check(float, int); static identity<char[8]>::type &check(double, int); static identity<char[9]>::type &check(long double, int); public: typedef typename cond<sizeof check(0 ? a : b, 0), A, B>::type type; }; // same type => finished template<typename A> struct promote<A, A> { typedef A type; };
如果您的Complex<T>
types可以相互转换,那么?:
将不会find一个通用types。 你可以专注于promote
,告诉它如何找出一个普通types的两个Complex<T>
:
template<typename T, typename U> struct promote<Complex<T>, Complex<U>> { typedef Complex<typename promote<T, U>::type> type; };
用法很简单:
int main() { promote<char, short>::type a; int *p0 = &a; promote<float, double>::type b; double *p1 = &b; promote<char*, string>::type c; string *p2 = &c; }
请注意,对于现实世界的使用,您应该最好记住一些我为了简单而忽略的情况,例如<const int, int>
应该类似于<T, T>
(最好先剥离const
和volatile
并将T[N]
到T*
和T&
到T
然后委托给实际的promote
模板 – 即在委托之前对A
和B
进行boost::remove_cv<boost::decay<T>>::type
)。 如果你不这样做, check
的电话将最终在这些案件模糊不清。