我在C ++中定义了一个类,它包含一个T
类型的标量数组,我想为它定义像sin,cos等运算符。用于定义应用于sin
的含义这个类的对象我需要知道应用于单个标量类型sin
的{{1}}的含义。这意味着我需要在类中使用适当的数学库(对应于标量类型T
)。这是现在的代码:
T
目前,我的代码公开了相应的数学库(使用命名空间std;),然后在我的类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)
}
的sin函数中使用::sin(a)
。虽然这有效,但它似乎是一个重大的黑客。
我看到C ++特征可用于存储特定于实例的信息(例如MyType
为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
参数化)?
答案 0 :(得分:5)
依赖于参数的查找不够好吗?
#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相同的命名空间中定义。如果你不希望这样,那么这可能无济于事......
答案 1 :(得分:0)
这不是您正在寻找的具体答案,但是不使用模板专业化是一个更简单的选择吗?
如......
template <typename T> T sin(T& t)
{
// does nothing
}
template <> float sin(float& t)
{
...
}
template <> double sin(double& t)
{
...
}
等等?
答案 2 :(得分:0)
我包括这个答案,因为我终于设法得到了我想要的东西(在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;
}