1

Tsin、cosなどの演算子を定義したい型のスカラーの配列を保持するクラスをC ++で定義しました。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)
}

現在、適切な数学ライブラリを公開し(namespace std;を使用)::sin(a)、クラスのsin関数内で使用するコードがありますMyType。これは機能しますが、大きなハックのようです。

TC ++特性を使用して、インスタンス固有の情報( is double、when TisBigNumなどの場合に使用する数学関数のセットなど)を格納できることがわかります。

私はこのようなことをしたいです:(これはコンパイルされないことは知っていますが、これが私がやりたいことを伝えてくれることを願っています)

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数学関数を含む正しい名前空間(によってパラメーター化された)を取得する方法はありますか?

4

3 に答える 3

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と同じ名前空間で定義されているため、これはXで機能しsin(X)ます。そうでないことが予想される場合、これはおそらく役に立ちません...

于 2010-08-07T19:41:13.167 に答える
0

私はついに私が欲しいものを手に入れることができたので、この答えを含めています(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;
}
于 2010-08-08T12:26:01.793 に答える
0

それはあなたが探している特定の答えではありませんが、テンプレートの特殊化を使用することはより簡単なオプションではないでしょうか?

のように...

template <typename T> T sin(T& t)
{
    // does nothing
}

template <> float sin(float& t)
{
    ...
}

template <> double sin(double& t)
{
    ...
}

等々?

于 2010-08-07T19:22:53.920 に答える