Ben*_*ter 7 c++ math templates boost
我一直在玩一套模板,用于在C++中给出两种原始类型来确定正确的促销类型.这个想法是,如果你定义一个自定义数字模板,你可以使用它们来确定,例如,基于传递给模板的类的操作符+函数的返回类型.例如:
// 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);
}
Run Code Online (Sandbox Code Playgroud)
如果您使用这些促销模板,则可以或多或少地将您的用户定义类型视为具有应用于它们的相同促销规则的原语.所以,我想我的问题是这可能是有用的吗?如果是这样,你想要什么样的常见任务,以便于使用?我的工作是假设单独使用促销模板不足以实际采用.
顺便提一下,Boost在其数学/工具/促销标题中有类似的东西,但它更多的是准备将值传递给标准C数学函数(期望2个整数或2个双精度)并绕过所有整数类型.是否更容易完全控制对象的转换方式?
TL; DR:您希望在推广本身的机制之外的算术推广标题中找到哪种辅助模板?
Joh*_*itb 12
为此,您可以使用的是?:操作员.它将为您提供两种类型之间的通用类型.首先,如果两种类型相同,你就可以了.然后,如果类型不同,则调用?:并查看您返回的类型.
您需要特殊的情况下,不提倡的类型char,short及其他们的签名/签名的版本,因为用于两种不同类型的这种操作数,结果将是他们都没有.您还需要注意两个类可以转换为提升的算术类型的情况.为了使这些正确,我们检查结果是否?:是一个提升的算术类型(在子句的精神中13.6),然后使用该类型.
// 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;
};
Run Code Online (Sandbox Code Playgroud)
如果您的Complex<T>类型可以相互转换,?:则不会找到常见类型.你可以专门promote告诉它如何找出一个常见的两种类型Complex<T>:
template<typename T, typename U>
struct promote<Complex<T>, Complex<U>> {
typedef Complex<typename promote<T, U>::type> type;
};
Run Code Online (Sandbox Code Playgroud)
用法很简单:
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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,对于真实世界的使用,你应该最好赶我离开了为简单起见,少数情况下,例如<const int, int>应如何处理类似<T, T>(您最好先带const和volatile并转换T[N]到T*和T&以T事后委托给实际的promote模板-即做boost::remove_cv<boost::decay<T>>::type对双方A并B委托他们之前).如果你不这样做,那么check对这些案件的调用最终将会产生歧义.
这绝对是有用的——我们在我工作的数学库中使用这些东西来正确地在表达式中输入中间值。例如,您可能有一个模板化的加法运算符:
template<typename Atype, typename Btype>
type_promote<Atype, Btype>::type operator+(Atype A, Btype B);
Run Code Online (Sandbox Code Playgroud)
这样,您可以编写一个泛型运算符来处理不同的参数类型,并且它将返回适当类型的值,以避免它出现的表达式中的精度损失。它也很有用(在向量和之类的事情中)在这些运算符中声明内部变量。
至于应该搭配什么的问题:我刚刚检查了我们定义它们的源代码,我们所拥有的只是您描述的简单的 ArithmeticPromotion 声明 - 三个通用版本来解决复杂-复杂、复杂的问题-real 和 real-complex 变体,使用特定的 real-real 变体,然后是 real-real 变体列表——总共大约 50 行代码。我们没有任何其他帮助器模板,而且(从我们的使用情况来看)它看起来不像我们会使用任何自然的模板。
(FWIW,如果您不想自己编写此代码,请从http://www.codesourcery.com/vsiplplusplus/2.2/download.html下载我们的源代码,然后取出src/vsip/core/promote.hpp。这甚至在我们库的 BSD 部分中-许可,尽管文件本身实际上并没有这么说。)
| 归档时间: |
|
| 查看次数: |
1855 次 |
| 最近记录: |