[英]Use different sets of functions based on template parameters (C++ traits?)
我已经在C ++中定义了一个类,其中包含一个类型为T
的标量数组,我想为其定义诸如sin,cos等运算符。为定义应用于该类对象的sin
的含义,我需要知道sin
应用于单标量类型T
这意味着我需要在该类中使用适当的数学库(对应于标量类型T
)。 这是现在的代码:
template<class T>
class MyType<T>
{
private:
std::vector<T> list;
// ...
template<class U> friend const UTP<U> sin(const UTP<U>& a);
template<class U> friend const UTP<U> cos(const UTP<U>& a);
template<class U> friend const UTP<U> tan(const UTP<U>& a);
//...
};
template<class T> const UTP<T> sin(const UTP<T>& a)
{
// use the sin(..) appropriate for type T here
// if T were double I want to use double std::sin(double)
// if T were BigNum I want to use BigNum somelib::bigtype::sin(BigNum)
}
目前,我有一些代码公开适当的数学库(使用命名空间std;),然后在类MyType
的sin函数内使用::sin(a)
。 尽管这可行,但似乎是一个主要的技巧。
我看到C ++特性可以用于存储实例特定的信息(例如,当T
为double
,当T
为BigNum
,使用哪种数学函数集,等等。)
我想做这样的事情:(我知道这不能编译,但是我希望这能传达我想要做的事情)
template<T>
struct MyType_traits {
};
template<>
struct MyType_traits<double> {
namespace math = std;
};
template<>
struct MyType_traits<BigNum> {
namespace math = somelib::bigtype;
};
然后将MyType类重新定义为:
template<T, traits = MyType_traits<T> >
class MyType
{
// ...
}
然后在我的朋友函数中使用traits::math::sin
。 有没有一种方法可以获取包含数学函数的正确名称空间(由T
参数化)?
基于参数的查找不够好吗?
#include <cmath>
#include <iostream>
namespace xxx {
class X
{
};
X sin(X) { return X(); }
} //xxx
std::ostream& operator<< (std::ostream& os, xxx::X)
{
return os << "X";
}
template <class T>
void use_sin(T t)
{
using std::sin; //primitive types are not in a namespace,
//and with some implementation sin(double) etc might not be available
//in global namespace
std::cout << sin(t) << '\n';
}
int main()
{
use_sin(1.0);
use_sin(xxx::X());
}
这对X有用,因为sin(X)
是在与X相同的名称空间中定义的。如果您不希望这样,那么这可能无济于事...
这不是您要查找的特定答案,但是使用模板专业化不是更简单的选择吗?
如...
template <typename T> T sin(T& t)
{
// does nothing
}
template <> float sin(float& t)
{
...
}
template <> double sin(double& t)
{
...
}
等等?
我之所以要包含此答案,是因为我终于设法得到了想要的东西(在irc.freenode.net上## c ++的非常好人的帮助下)。 此方法使ADL以及一组静态位置(xxx :: math)都可以查找数学函数的定义。
这样,如果类Test的类型参数T满足以下条件:
库看起来像这样:
#include <vector>
#include <cmath>
namespace xxx {
// include the usual math
namespace math {
using std::asin;
}
template <class T>
class Test
{
std::vector<T> array;
public:
Test(const typename std::vector<T>::size_type length)
{
assert(length >= 1);
array.assign(length, T(0.0));
}
friend std::ostream& operator<<(std::ostream& out, const Test<T>& a)
{
out << "(";
std::copy(a.array.begin(), a.array.end(), std::ostream_iterator<T>(out, ", "));
out << "\b\b)";
return out;
}
template<class U> friend const Test<U> asin(const Test<U>& a);
};
template<class U> const Test<U> asin(const Test<U>& a)
{
using math::asin;
Test<U> ret(a.array.size());
for (typename std::vector<U>::size_type i = 0; i < a.array.size(); ++i)
ret.array[i] = asin(a.array[i]);
// note how we use have a using math::asin; and then a call to asin(..) here,
// instead of a math::asin(..). This allows for ADL.
return ret;
}
} // xxx
客户看起来像这样:
#include <iostream>
#include <boost/math/complex.hpp>
// client, with some foresight, includes complex math
namespace xxx { namespace math {
using boost::math::asin;
} }
#include "test.h"
// demo
int main(int argc, char **argv)
{
using std::cout; using std::endl;
xxx::Test<double> atest(3);
cout << "atest: " << atest << endl;
cout << "asin(atest): " << asin(atest) << endl;
cout << endl;
xxx::Test<std::complex<double> > btest(3);
cout << "btest: " << btest << endl;
cout << "asin(btest): " << asin(btest) << endl;
cout << endl;
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.