14

テンプレート関数「foo」があるとしましょう。

template<class T>
void foo(T arg)
{ ... }

私は特定のタイプに特化することができます、例えば

template<>
void foo(int arg)
{ ... }

すべての組み込み数値型(int、float、doubleなど)に同じ特殊化を使用したい場合は、それらの行を何度も記述します。bodyを別の関数にスローできることは知っています。これを呼び出すだけで、すべてのスペシャライゼーションのbodyで呼び出されますが、すべてのタイプに対してこの「void foo(...」」を記述しないようにするとよいでしょう。このすべてのタイプにこの特殊化を使用したいことをコンパイラーに伝える可能性はありますか?

4

6 に答える 6

19

std::numeric_limits型が数値型であるかどうかを確認するために使用できます(is_specializedすべての浮動小数点型と整数型の基本型に当てはまります)。

// small utility
template<bool> struct bool2type { };

// numeric
template<typename T>
void fooImpl(T arg, bool2type<true>) {

}

// not numeric
template<typename T>
void fooImpl(T arg, bool2type<false>) {

}

template<class T>
void foo(T arg)
{ fooImpl(arg, bool2type<std::numeric_limits<T>::is_specialized>()); }
于 2010-03-12T02:19:40.500 に答える
3

プリプロセッサを使用したアプローチを使用できます。

foo.inc:

template<>
void foo(TYPE arg)
{ /* do something for int, double, etc. */ }

foo.h:

template<class T>
void foo(T arg)
{ /*do something */ }

#define TYPE int
#include "foo.inc"
#undef TYPE

#define TYPE double
#include "foo.inc"
#undef TYPE

于 2010-03-12T02:20:53.817 に答える
3

ブーストあり:

#include <boost/type_traits/is_scalar.hpp>
#include <iostream>
#include <string>

namespace detail
{
    typedef const boost::true_type& true_tag;
    typedef const boost::false_type& false_tag;

    template <typename T>
    void foo(const T& pX, true_tag)
    {
        std::cout << "special: " << pX << std::endl;
    }

    template <typename T>
    void foo(const T& pX, false_tag)
    {
        std::cout << "generic: " << pX << std::endl;
    }
}

template <typename T>
void foo(const T& pX)
{
    detail::foo(pX, boost::is_scalar<T>());
}

int main()
{
    std::string s = ":D";
    foo(s);
    foo(5);
}

ほとんどの場合、ブーストなしで簡単に実行できます。

#include <iostream>
#include <string>

// boolean stuff
template <bool B>
struct bool_type {};

typedef bool_type<true> true_type;
typedef bool_type<false> false_type;

// trait stuff
template <typename T>
struct is_scalar : false_type
{
    static const bool value = false;
};

#define IS_SCALAR(x) template <> \
            struct is_scalar<x> : true_type \
            { \
                static const bool value = true; \
            };

IS_SCALAR(int)
IS_SCALAR(unsigned)
IS_SCALAR(float)
IS_SCALAR(double)
// and so on

namespace detail
{
    typedef const true_type& true_tag;
    typedef const false_type& false_tag;

    template <typename T>
    void foo(const T& pX, true_tag)
    {
        std::cout << "special: " << pX << std::endl;
    }

    template <typename T>
    void foo(const T& pX, false_tag)
    {
        std::cout << "generic: " << pX << std::endl;
    }
}

template <typename T>
void foo(const T& pX)
{
    detail::foo(pX, is_scalar<T>());
}

int main()
{
    std::string s = ":D";
    foo(s);
    foo(5);
}
于 2010-03-12T02:28:17.423 に答える
0

おそらく、すべてのネイティブタイプで機能するデフォルトのテンプレート関数を定義し、カスタムタイプの特殊化をユーザーに委任することができます

于 2010-03-12T02:10:14.440 に答える
0

小さなスクリプト(Perlなど)を作成して、ソースファイルを生成することができます。特殊化するすべてのタイプを含む配列を作成し、それぞれの関数ヘッダーを書き出すようにします。スクリプト実行をmakefileに埋め込んで、何かを変更した場合に自動的に再実行することもできます。

注:これは、実装fooを各タイプで簡単かつ類似させることができることを前提としています。たとえば、実際の実装関数を呼び出すだけです。しかし、将来のメンテナが頭を悩ませる可能性のある一連のテンプレート/プリプロセッサのマンボジャンボを回避します。

于 2010-03-12T02:28:51.230 に答える
0

これがヨハネスのソリューションの改良版ですが、読みやすくなっています。関数内で型チェックを行うだけです。

template<typename T>
void foo(T arg)
{
  if (numeric_limits<T>::is_specialized)  // not a runtime check - compile time constant
  {
  }
  else
  {
  }
}

タイプ特性(それ自体がテンプレートの特殊化)を使用すると、一連のテンプレートの特殊化を単一の読みやすい関数テンプレートに置き換えることができます。

于 2019-03-06T23:53:58.053 に答える