lix::Failable

lix::Succession が失敗したときにエラーコードを返す、というだけのものであるのに対して、何らかの値を取得し、失敗時はエラーコードを返す、という場合に使用することを想定したクラステンプレートです。

    // 何らかの文字列を引数で受けた string に格納して返す、失敗時は false を返し、その理由は GetLastError で取得できる。
    bool GetSomeText( std::string& ret );

というシグネチャ(ここでは『失敗理由はGetLastErrorで』ということも意味的なシグネチャと捉えます。)が

    lix::WinFailable<std::string> GetSomeText();

になります。Failable は boost::optional っぽい形式で内容にアクセスできます。

lix::WinFailable<std::string> GetText( int i )
{
    if( i < 0 ){
        // ホントはなんか API を呼ぶ、その副作用で LastError が変わる。
        SetLastError( ERROR_INVALID_PARAMETER );
        return lix::Failed(GetLastError());
    }

    return "てきすと";
}

void sampleA(){
    lix::WinFailable<std::string> r = GetText( 1 );
    assert( r );

    cout << r << endl; // これは内容が流れ、 "てきすと" と表示される。

    std::string content = *r; // 値はこうやってとる。
    content = r.Get();        // これでもいいけど . と -> の両方があるので、
                              // 混乱しそう。成功時はとっとと * したほうがいいと思う・

    r = GetText(-1);

    // if( r.IsFailed()) でも同じ
    if( !r ){
        // 失敗。

        // エラーコードを返す。
        DWORD err = r.GetErrorCode();

        // メッセージを返す。
        string message = r.GetErrorMessage();

        // ストリームにも流せたりする。(これは内容ではなくエラーメッセージが流れる)
        cerr << r << endl; 
    }

    r = GetText(-1);
    std::string x = r.GetValueOr("でふぉると"); // 成功してたら内容を、失敗してたら引数を返す。
    cout << x << endl; // この表示は "でふぉると"
}

lix::WinFailable は lix::Failable の テンプレートエイリアス・・・とは今のところいかないので、FailableBase という基底クラスを作り、そこから継承してひとつだけテンプレートパラメータを残しています。

    template< typename T, typename ErrorCodeType, typename ErrorCategory = ErrorCodeTraits<ErrorCodeType> >
    class FailableBase {
        ...
    };
    
    // こう書きたいんだけどね・・・
    // template <typename T>
    // using WinFailable = FailableBase<T, DWORD, Win32ErrorCategory >;
    
    // いまのところこうせざるをえない。
    template< typename T>
    class WinFailable : public FailableBase<T, DWORD, Win32ErrorCategory> {
        ...
    };

ErrorCategory は lix::Succeesion と同じもので、エラーコードをどうやって文字列化するか、というポリシーです。errno版とGetLastError版が存在しています。
各エラー体系に合わせて ErrorCategory を作ってあげれば、エラーコードがどんなものであっても、

    auto r = HogeHoge();
    if( !r ){
        // エラーハンドリング
    
        // return するか、 throw するか。
    }
    
    // 改めて取り出す
    string s = *r;

というスタイルが使用できますし、boost::optional を使用してよくやるスタイル

    if( auto r = HogeHoge() ){
        string s = *r;
        
        // 正常時の処理をここに。
    }else{
        // 異常時の処理はここに。
    }

を、エラー時の情報を殺すことなく行うことが出来ます。