1

次のテンプレート関数があるとします。

// #include <iostream>

template< typename T >
T read( std::istream& in )
{
    T x;
    in >> x;  // (could check for failure, but not the point)
    return x;
}

次のように使用することを意図しています (constユーザー入力から変数を初期化するため)。

// #include <string>
// std::istream& in = std::cin;

const int integer = read< int >( in );
const double decimal = read< double >( in );
const std::string word = read< std::string >( in );
...

ただし、同じ型を 2 回指定する必要があることに注意してください。1は変数宣言用、もう 1 回は呼び出し用です。このような重複は避けたほうがよいでしょう ( DRY の原則、「Don't Repeat Yourself」も参照)。各変更は重複する必要があり、たとえば次のようなコードが必要になるためです。

const int integer = read< double >( in );
const double decimal = read< int >( in );
const std::string word = read< char* >( in );

「正常に」コンパイルされますが、おそらく実行時に悪いことをします(特に3番目のものは警告を引き起こします)。

型の繰り返しを避ける方法はありますか?


私はすでに 2 つの方法を考えているので、知らないふりをする代わりに、もっと質問する前にすぐにそれらを公開しています。

  1. 戻り型リゾルバー

    最近、「Return Type Resolver」イディオムを発見しました(この質問から)。したがって、既存の関数の周りにテンプレートの暗黙的な変換演算子を使用して単純なクラスを作成できます。

    class Read {
        std::istream& m_in;
    public:
        explicit Read( std::istream& in ) : m_in( in ) { }
    
        template< typename T >
        operator T() const
        {
            return read< T >( m_in );
        }
    };
    

    そして、次のようなコードを書くことができます:

    const int integer = Read( in );
    const double decimal = Read( in );
    const std::string word = Read( in );
    ...
    

    ここで、「戻り値の型」は変数の型から自動的に推定されます (注:const変数がそうであっても戻り値の型はそうではないため、これは元のコードと真に同等です (特にインライン化の可能性がある後))。

  2. C++11auto

    C++11以降では、代わりauto指定子を使用できます。これにより、型の名前を 2 回指定することも回避できますが、アプローチは「逆」です。

    const auto integer = read< int >( in );
    const auto decimal = read< double >( in );
    const auto word = read< std::string >( in );
    ...
    

    ここで、変数の型は戻り値の型から自動的に推測されます。

他に何か?

さて、あなたは他の選択肢を知っていますか?[この質問の「理由」については、以下のコメントへの私の返信を参照してください。]

ありがとうございました。

4

2 に答える 2

1

文体上の理由で気に入らないかもしれませんが、それでもプリプロセッサを使用できます。次のように使用できます。

#define READ(type, variable, stream) type variable = read<type>(stream)

この後、次のように簡単に課題を書くことができます

READ(int, integer, in);

もちろん、これは変数の定義とその初期化を関数のような構造の背後に隠しますが、これは私は好きではありませんが、可能な解決策です。

于 2013-07-24T16:11:26.983 に答える