根据模板参数使用不同的函数集(C ++特征?)

时间:2010-08-07 19:10:25

标签: c++ templates traits

我在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 ++特征可用于存储特定于实例的信息(例如MyTypeTdoubleT 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参数化)?

3 个答案:

答案 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是这样的:

  1. 如果T将数学函数定义为成员,那么我们可以使用ADL而不是触摸(添加到)命名空间xxx :: math。
  2. 如果T没有将数学函数定义为成员但使用特定命名空间中的函数,那么我们可以添加到命名空间xxx :: math,如下例所示。
  3. 图书馆看起来像这样:

    #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;
    }