5

基本的にstd::enable_if:パラメータとテンプレートパラメータと同じことをしようとしていますが、コードをコンパイルできません。

パラメータにstd::enable_ifがあり、正常に動作する単純な最初のバージョンがありました。

#include <iostream>
#include <type_traits>

template <typename T>
void foo(T t, typename std::enable_if< std::is_same<T, int>::value >::type* = 0) {
  std::cout << "int" << std::endl;
}

template <typename T>
void foo(T t, typename std::enable_if< !std::is_same<T, int>::value >::type* = 0) {
  std::cout << "not int" << std::endl;
}

int main(int argc, char* argv[])
{
  foo(10);
  foo(10.1);
  return 0;
}

しかし、テンプレートのものが1つの場所にあり、関数の引数からenable_ifが必要な場合は、より簡潔になると思いました。

ここで、enable_if部分を移動するだけで、次のようになります。

#pragma warning(1 : 4519)

#include <iostream>
#include <type_traits>

template <typename T, typename std::enable_if< std::is_same<T, int>::value >::type = 0>
void foo(T t) {
  std::cout << "int" << std::endl;
}

template <typename T, typename std::enable_if< !std::is_same<T, int>::value >::type = 0>
void foo(T t) {
  std::cout << "not int" << std::endl;
}

int main(int argc, char* argv[])
{
  foo(10);
  foo(10.1);
  return 0;
}

#pragma warning(1:4519)必要だったのは、関数テンプレートのデフォルトの引数がVS2010のエラーであるためです。問題は、それでもコンパイルされないことです。最初のメッセージは次のとおりです。error C2783: 'void foo(T)' : could not deduce template argument for '__formal' それはやりたくないのですが、次のように呼び出して、必要なテンプレートを明示的に記述してみました。

  foo<int, int>(10);
  foo<double, double>(10.1);

しかし、それでも機能せず、新しいエラーが発生します。

error C2975: 'foo' : invalid template argument for 'unnamed-parameter', expected compile-time constant expression

誰かがこれを修正する方法を教えてくれることを願っています。もちろん、私のスタイルやコードにある可能性のあるその他の問題に関するすべてのコメントを歓迎します。:)

追加の質問:VS2010がデフォルトで関数テンプレートのデフォルト引数を許可しない理由を誰かが知っていますか?

4

3 に答える 3

11

問題は、の2番目のテンプレートパラメータがstd::enable_ifデフォルトでになっていることvoidです。だからあなたはほとんど同じことをしている:

template <typename T, void = 0>

これにより、置換は常に失敗します。タイプの非タイプテンプレート引数を使用できますint。これには、デフォルトの0値を指定できます。

template <typename T, typename std::enable_if< std::is_same<T, int>::value, int >::type = 0>

両方のオーバーロードに対して同じことを行うと、機能します。

ここでデモ。

于 2012-08-27T12:14:11.453 に答える
5

デフォルトはtype= 0には意味がありません。代わりに、デフォルトのタイプが必要です:

template <typename T, typename = typename std::enable_if<cnd>::type>
void foo(T) { /* ... */ }

foo2 番目の引数の既定の型が存在する場合、つまり条件が true の場合にのみ、オーバーロードの解決に参加するようになりました。

ちなみに、関数テンプレートのデフォルトのテンプレート引数は、C++11 で新しく導入されました。(それらは以前は単に忘れられていました。)

複数のオーバーロードが必要な場合、同じテンプレート署名を繰り返してはならないため、これは面倒になることに注意してください。各オーバーロードにダミーのテンプレート引数の個別のセットを与えることもできますが、それではうまくスケーリングできません。この投稿は、可変個引数テンプレート パックを使用したより良いソリューションを示しています (こちらからも入手できます)。

于 2012-08-27T12:10:46.633 に答える
1

この状況では、enable_if の代わりに、単純なオーバーロードを実行できます。

#include <iostream>

void foo(int) {
  std::cout << "int" << std::endl;
}

template <typename T>
void foo(T) {
  std::cout << "not int" << std::endl;
}

int main(int argc, char* argv[])
{
  foo(10);
  foo(10.1);
  return 0;
}

引数が int でない場合にコンパイラにテンプレートを選択させる完全一致が優先されます。int を指定した場合、2 つの完全一致があり、非テンプレートが優先されます。テンプレートを C++11 の方法でさらに制約したい場合は、次のように記述できます。

#include <iostream>
#include <type_traits>

#define REQUIRES(...) ,class=typename std::enable_if<(__VA_ARGS__)>::type

void foo(int) {
  std::cout << "int" << std::endl;
}

template <typename T
  REQUIRES(!std::is_same<T,int>::value)
>
void foo(T) {
  std::cout << "not int" << std::endl;
}

int main(int argc, char* argv[])
{
  foo(10);
  foo(10.1);
  return 0;
}

これにより、オーバーロードの解決が完了する前に、オーバーロードの解決セットからテンプレートが除外されます。しかし、私が言ったように、T=int の場合、とにかく非テンプレートが勝つでしょう。

于 2012-08-27T12:46:40.253 に答える