5

このリンクは私の質問に答えないので、ここで質問します。

基本的にはテンプレート関数を書きたい

template <typename Out, typename In>
Out f(In x);

Outここでは、 を呼び出すときに常に指定する必要がありますf。毎回やりたくないので基本的にはやりたい

template <typename Out = In, typename In>
Out f(In x);

つまり、指定しない場合Out、デフォルトで になりますIn。ただし、これは C++11 では不可能です。

だから私の質問は、効果を達成する方法はありますか?

  1. 呼び出しf(t)はインスタンス化するf<T,T>(t)か、より一般的にf<typename SomeThing<T>::type, T>
  2. 呼び出すf<U>(t)とインスタンス化されますf<U, T>(t)
4

3 に答える 3

8

あなたはおそらく特定したくないでしょうInが、むしろそれを推測していますよね?

この場合、関数をオーバーロードする必要があります。

template <typename Out, In>
Out f(In x);

template <typename T>
T f(T x);

あれを呼べ:

f(42);
f<float>(42);

…しかし、残念ながらそれはあいまいですf<int>(42)。いずれにせよ、SFINAE を使用してオーバーロードの 1 つを適切に無効にすることができます。

template <
    typename Out,
    typename In,
    typename = typename std::enable_if<not std::is_same<Out, In>::value>::type
>
Out f(In x);

template <typename T>
T f(T x);

実装の冗長性を避けるために、両方の関数を共通の実装にディスパッチさせf_implます。

これが実際の例です:

template <typename Out, typename In>
Out f_impl(In x) {
    std::cout << "f<" << typeid(Out).name() <<
                 ", " << typeid(In).name() <<
                 ">(" << x << ")\n";
    return x;
}

template <
    typename Out,
    typename In,
    typename = typename std::enable_if<not std::is_same<Out, In>::value>::type
>
Out f(In x) {
    std::cout << "f<Out, In>(x):\t ";
    return f_impl<Out, In>(x);
}

template <typename T>
T f(T x) {
    std::cout << "f<T>(x):\t ";
    return f_impl<T, T>(x);
}


int main() {
    f(42);
    f<float>(42);
    f<int>(42);
}
于 2013-01-24T19:12:04.347 に答える
4

ここでは必要ないかもしれませんが、古典的なテクニックを次に示します。

struct Default
{
  template <typename Argument, typename Value>
    struct Get {
      typedef Argument type;
    };

  template <typename Value>
    struct Get <Default, Value> {
      typedef Value type;
    };
};

template <typename Out = Default, typename In>
typename Default::Get<Out, In>::type f(In x);
于 2013-01-24T19:25:55.800 に答える
2

ここに完璧なソリューションがあります! f<const int&>ここで使用されている手法とは関係なく、関数は一時への参照を返すことができないため、機能しません。

[hidden]$ cat a.cpp
#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;

template <typename Out, typename In>
Out f_impl(In x) {
  cout << "Out=" << typeid(Out).name() << " " << "In=" << typeid(In).name() << endl;
  return Out();
}

template <typename T, typename... Args>
struct FirstOf {
  typedef T type;
};

template <typename T, typename U>
struct SecondOf {
  typedef U type;
};

template <typename... Args, typename In>
typename enable_if<sizeof...(Args) <= 1, typename FirstOf<Args..., In>::type>::type f(In x) {
  typedef typename FirstOf<Args..., In>::type Out;
  return f_impl<Out, In>(x);
}

template <typename... Args, typename In>
typename enable_if<sizeof...(Args) == 2, typename FirstOf<Args...>::type>::type f(In x) {
  typedef typename FirstOf<Args...>::type Out;
  typedef typename SecondOf<Args...>::type RealIn;
  return f_impl<Out, RealIn>(x);
}

int main() {
  f(1);
  f(1.0);
  f<double>(1);
  f<int>(1.0);
  f<int>(1);
  f<const int>(1);
  f<int, double>(1);
  f<int, int>(1);
  f<double, double>(1);
}
[hidden]$ g++ -std=c++11 a.cpp
[hidden]$ ./a.out
Out=i In=i
Out=d In=d
Out=d In=i
Out=i In=d
Out=i In=i
Out=i In=i
Out=i In=d
Out=i In=i
Out=d In=d
于 2013-01-24T20:31:04.970 に答える