-2

それぞれが4つのオーバーロードを持つ関数のセットを定義したいとします。最初のオーバーロードはタイプの単一のパラメーターをint32_t取り、2番目int64_tは、3番目uint32_tと4番目を取りuint64_tます。関数ごとに、すべてのオーバーロードの実装が同じであるため、代わりに関数テンプレートを定義できます。

template <typename T>
void f(T t) {
  // ...
}

ただし、これは4つのオーバーロードがある場合とは異なります。これは、インスタンス化に使用できる(整数)タイプごとに個別の関数があるためfです。ただし、の実装の詳細はf、他の整数型では機能しない可能性があるようなものです。これに対処するために、関数テンプレートを4つのオーバーロードされた関数でラップできます。

template <typename T>
void f_impl(T t) {
  // ...
}

void f(int32_t value) { f_impl(value); }
void f(int64_t value) { f_impl(value); }
void f(uint32_t value) { f_impl(value); }
void f(uint64_t value) { f_impl(value); }

これは機能しますが、関数ごとにかなりの量のコードが必要です(4つの関数のオーバーロード+1つの関数テンプレート)。これを単純化する方法はありますか?

明確にするために、テンプレートを直接使用することは望ましくありません。これは、、、、および。以外のタイプに特化することは(実装上の理由またはその他の理由で)意味がないためint32_tです。int64_tuint32_tuint64_t


私はstd::enable_ifすでに使用してみましたが、その問題は次の例で最もよく示されています。

#include <type_traits>
#include <iostream>

template <typename T>
struct is_supported_int {
  static const bool value = false;
};

template <>
struct is_supported_int<int32_t> {
  static const bool value = true;
};

template <>
struct is_supported_int<int64_t> {
  static const bool value = true;
};

// ...

template <typename T, typename = typename std::enable_if<is_supported_int<T>::value, T>::type>
void f(T t) {
// ...
}

int main() {
  short s = 42;
  f(s);
}

私がエミュレートしようとしているオーバーロードのある元のバージョンとは異なり、この例はf、の一致する関数のセットから除外されるため、コンパイルされませんshort

残念ながら、Rapptzが提案したように、この関数の実装の詳細は特定の型に対してのみ定義でき、すべての整数型に対しては定義できstd::is_integral<T>ないため、どちらも役に立ちません。f

4

2 に答える 2

5

このようなものが機能します。

#include <type_traits>
#include <iostream>

template<typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
void f(T t) {
    std::cout << "int types only!\n";
}

int main() {
    f(1.234f);
    f(12);
}

f(1.234f)はコンパイルに失敗しますが、f(12)はコンパイルに失敗しません。

于 2013-01-13T18:31:01.053 に答える
0

enable_ifまたは静的アサートを使用して、インスタンス化を制限します。

#include <type_traits>
#include <cstdint>

template<bool X, bool Y>
struct or_ : std::true_type 
{};

template<>
struct or_<false, false> : std::false_type 
{};

template<typename T>
struct valid_type_for_f :
  or_< std::is_same<T, std::uint32_t>::value,
       std::is_same<T, std::uint64_t>::value> // etc.
{};

// static assert
template<typename T>
T f(T t) {
  static_assert(valid_type_for_f<T>::value, "Not a valid type");
  return t;
}

// enable_if
template<typename T>
typename std::enable_if<valid_type_for_f<T>::value, T>::type
fenable(T t) {
  return t;
}


int main()
{
  float x = 4.2f;
  f(x); // fails
  fenable(x); // fails
  std::uint32_t xx = 23;
  f(xx);
  fenable(xx);
  return 0;
}
于 2013-01-13T18:42:20.720 に答える