2

テンプレートの部分的な特殊化を使用して、関数/メソッドを作成したいと思います:

A)仮パラメータの特定のプリミティブ型(int、double、floatなど)を1つだけ処理し、例外をスローする他の型を処理する

template <class T>
T min ( Point <T> p )
{
    /*if (T == int) continue;
    else throw exception*/
}

B) 仮パラメータのより多くの非プリミティブ型 (ユーザー定義型) の処理、および例外をスローする他の型の処理...

いくつかのコード例が役立ちます (c++ ブースト ライブラリなし)。ご協力いただきありがとうございます。

4

3 に答える 3

7

これが問題の解決策です (パート A)。

template<bool b> struct compile_time_assert;

template<> 
struct compile_time_assert<true> 
{};

template<class T> 
struct is_int 
{ 
     static const bool value = false; 
};
template<> 
struct is_int<int> 
{ 
     static const bool value = true; 
};

template <class T>
T min ( Point <T> p )
{
    /* 
     since you can check error at compile time, there is no reason to 
     raise exception (which is at runtime) if T is not int! 
     the following assert will not compile if T is not int.
     not only that, you can even see the error message "_error_T_is_not_int" 
     if T is not int;
    */

    compile_time_assert<is_int<T>::value> _error_T_is_not_int;

    //your code
}

これらのサンプル コードを参照してください。

  1. Tがintの場合のサンプルコード1 。エラーなし。ただし、警告は無視してください。
  2. Tがdoubleの場合のサンプルコード2。ここで、エラー メッセージも参照してください。ただし、警告は無視してください。

同様に、他の型 (double、char など) のテンプレートを作成できます。または、さらに良いことに、これらすべてを 1 つの に単純にマージしstruct代わりに. などなど、実験をしてみよう!static const bool is_T_int = true;

しかし、関数で 1 つの型だけを処理したいのであれば、最初からテンプレートを定義する必要はありません。


パート (B) については、上記からアイデアを得ることができます。右?実験を行います!

于 2010-12-14T17:44:09.007 に答える
1

ここでパート B に boost::mpl を使用できますが、これは boost:( を使用します。

#include <boost/mpl/at.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/bool.hpp>

using namespace boost;

typedef mpl::map<
    mpl::pair<int, mpl::true_>,
    mpl::pair<double, mpl::false_>,
    mpl::pair<float, mpl::false_>
> TAllowedTypesForMin;

template <class T>
T min (T p)
{
    const bool allowed = mpl::at<TAllowedTypesForMin, T>::type::value;
    if (allowed)
    {

    }

    return p;
}

編集

コンパイル時のチェックを使用すると、すべてが簡単になります。

#include <boost/mpl/set.hpp>
#include <boost/mpl/assert.hpp>

using namespace boost;

template<class T> struct Point {};
typedef mpl::set<int, double, float> TAllowedTypesForMin;

template <class T>
T min (Point<T> p)
{
    typedef mpl::has_key<TAllowedTypesForMin, T> allowedType;
    BOOST_MPL_ASSERT_MSG( allowedType::value, NOT_SUPPORTED_TYPE, () );

// do something

    return T();
}

int main() 
{
        min(Point<long>());
        return 0;
}
于 2010-12-14T18:03:47.790 に答える
1

Alexender C. のコメントで述べたように、コンパイル エラーの方が適切ではないでしょうか?

template <typename T> struct GateKeeper;

// Func we want to call
template <typename S, typename T> void foo (T t);

// Warpper that checks the type and forwards the call
template <typename T> inline void foo (T t)
{
  //
  // This call will fail for unless a specialization of
  // GateKeeper for `T` is defined with a member TYPE
  foo< typename GateKeeper<T>::TYPE, T > ( t );
}

//
// This declaration "allows" the type int.
template <> struct GateKeeper<int> { typedef int TYPE; };

void bar ()
{
  foo (0);   // Compiles
  foo (0.0); // Causes error in wrapping foo
}

部分的な特殊化を使用して、特定のテンプレートの特殊化を許可できます。

// Some template type
template <typename T>
class TmplType
{
};

// This allows for specializations of TmplType
template <typename T> struct GateKeeper< TmplType<T> > { typedef int TYPE; };

void bar ()
{
  TmplType<char> tt;
  foo (tt);   // Compiles
}

サポートしたいタイプごとに、新しい専門分野を追加します。

更新: 何が起きているか:

注:テンプレート パラメーター名を元のバージョンから変更して、少しわかりやすくしました。

コンパイラfoo(x)が正しく特殊化できる唯一の関数への呼び出しを確認すると、 foo<T>(T). これは、 のすべてのテンプレート パラメータを推測できないためfoo<S,T>(T)です。

の本体はfoo<T>(T)、呼び出しを実際の関数に転送します。

foo< typename GateKeeper<T>::TYPE, T > ( t );

(余談: typenameをいつ使用するかについては、こちらを参照してください)

これは一度に2つのことをしています。

1 つ目は、他の関数を呼び出すために必要な 2 つのテンプレート パラメーター (S と T) を提供することです。

GateKeeper<T>2 つ目は、この別の型としてのメンバーを使用することです。型GateKeeper<T>は完全であり、そのメンバーを持っている必要があります。このチェックにより、許可するタイプと許可しないタイプを指定できます。

template <typename T> struct GateKeeper;                  // Incomplete
template <> struct GateKeeper<int> { typedef int TYPE; }; // Complete

の定義のみを提供し、 の定義を提供してGateKeeper<int>いないためGateKeeper<double>、 への呼び出しはfoo(0)正しくfoo(0.0)機能し、コンパイル エラーで失敗します。

を許可するdoubleには、明示的な特殊化を追加するだけです。

template <> struct GateKeeper<double> { typedef int TYPE; }; // double now works.
于 2010-12-14T19:04:27.250 に答える