0
// First try this:

template <class T> T Read(istream& in) {
  T t;
  in >> t;
  return t;
}

// If there is no operator>>(istream&, T) try this: 

template <class T> T Read(istream& in) {
  return T (in);
}

// If there is no constructor T(istream&) try this:

template <class T> T Read(istream& in) {
  return T::OfStream (in);
}

// now fail.

これは実装できますか?

そうでない場合、代替手段は何ですか?

4

5 に答える 5

8

SFINAEのコンセプトをご存知ですか?この概念を使用すると、テンプレート引数の任意のプロパティに基づいて、関数テンプレートを候補セットに含めたり除外したりできます。ただし、Alex Martelli が言ったように、これはメソッドの本体ではなく、シグネチャで発生させる必要があります。

これは、タイプ T のいくつかのプロパティに関してコンパイル時に決定を下すことができる必要があることを意味し、その決定の結果を使用して、テンプレートの署名を強制的に無効にする必要があります。これにより、コンパイルを発生させることなく、コンパイラの候補セットからそのテンプレートが除外されます。エラー。

Boost には、これを容易にする 2 つのライブラリがあります。Boost.TypeTraitsでは、「T は配列ですか?」などの質問ができます。または「T はポインタですか?」または「T は U のサブクラスですか?」コンパイル時に。そのクエリの結果をBoost.EnableIfで使用して、関数を除外することができます (必要に応じて除外することもできます)。

これらのライブラリを組み合わせて使用​​すると、現在の状態を達成できる場合があります。特定のコンパイラを使用している場合は、コンパイラ固有の拡張機能を使用して同様の結果を達成できる場合もあります (それが問題ない場合)。たとえば、MSVC を使用すると、__if_existsキーワードを利用できる場合があります。単純な例が実際にやりたいことをどれだけ正確に反映しているかによって、一方の方法がもう一方の方法よりもきれいになる場合があります。

于 2009-10-29T02:50:15.317 に答える
1

前述のとおり、これらはあいまいです。enable_ifと組み合わせて、ブーストなどを検討する必要がありますis_function

于 2009-10-29T02:47:02.077 に答える
0

標準準拠の C++ 実装では、これらの複数のあいまいなテンプレートはエラーを生成する必要があります (あいまいさは、本文ではなく署名によって定義されます)。このコードを許可する範囲で標準に違反している C++ コンパイラを私は知りません (それは、クレイジーなほど十分なコンパイラが存在しないという意味ではありません。

于 2009-10-29T02:36:22.043 に答える
0

これは、指定したとおりに直接実装することはできませんが、回避策があります。テンプレート変換演算子を定義することが可能であり、その型パラメーターは予想されるターゲット型から推測できます。したがって、プロキシ クラスを導入できます。

class read_proxy
{
public:
    read_proxy(std::istream& in) : in(in) {}
    template<class T> operator T () { T x; in >> x; return x; }
private:
    std::istream& in;
};

read_proxy read(std::istream& in)
{
    return read_proxy(in);
}

そして、あなたが最初に望んでいたようにそれを使用してください:

void foo(float) {}

int main()
{
    int x = read(std::cin);
    foo(read(std::cin)); // float
}

ここでの潜在的な問題は、誰かが返されたプロキシ自体を永続化しようとすると、ライフタイムの問題に遭遇する可能性があることです (ストリームへの単純な参照を保持し、後者はプロキシが破壊される前に破棄される可能性があるため)。

于 2009-10-29T02:47:57.037 に答える
0

他の回答が示すように、標準に準拠していません。

意図した使用法を示していないため、正確に何を求めているのかを理解するのは少し難しいですが、コードを自分で実装できます (以下を参照)。これは、特定のクラスごとに変換テンプレートを作成することを避けるために、SFINAE でさらに改善できます。

#include <iostream>
#include <sstream>

using namespace std;

struct A
{
    int x;
    A() : x(0) {}
};

istream& operator>>(istream& in, A& a)
{
    in >> a.x;
    return in;
}

ostream& operator<<(ostream& on, A& a) { return on << "A: " << a.x; }

struct B
{
    int x;
    B(istream& in) : x(0) { in >> x; }
};

ostream& operator<<(ostream& on, B& b) { return on << "B: " << b.x; }

struct C
{
    int x;
    C() : x(0) {}

    static C OfStreamX(istream& in)
    {
        C c;
        in >> c.x;
        return c;
    }
};

ostream& operator<<(ostream& on, C& c) { return on << "C: " << c.x; }

template <typename T> T Read(istream& in);
template <> A Read(istream& in)
{
    A a;
    in >> a;
    return a;
}

template <> B Read(istream& in) { return B(in); }
template <> C Read(istream& in) { return C::OfStreamX(in); }

int main()
{
    string data("23 45 67");
    istringstream in(data);

    A a = Read<A>(in);
    cout << a << endl;

    B b = Read<B>(in);
    cout << b << endl;

    C c = Read<C>(in);
    cout << c << endl;
}

出力:

A: 23
B: 45
C: 67
于 2009-10-29T03:21:59.270 に答える