繁体   English   中英

根据模板参数使用不同的功能集(C ++特性?)

[英]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 ++特性可以用于存储实例特定的信息(例如,当Tdouble ,当TBigNum ,使用哪种数学函数集,等等。)

我想做这样的事情:(我知道这不能编译,但是我希望这能传达我想要做的事情)

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满足以下条件:

  1. 如果T将数学函数定义为成员,那么我们可以使用ADL而不触摸(添加)命名空间xxx :: math。
  2. 如果T没有将数学函数定义为成员,而是使用特定命名空间中的函数,则可以像下面的示例一样将其添加到命名空间xxx :: math中。

看起来像这样:

#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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM