tl::expected

エラーハンドリングC++関数型プログラミング値検証モナド例外なし

ライブラリ

tl::expected

概要

tl::expectedは、C++23のstd::expectedのバックポート実装で、関数型プログラミングスタイルのエラーハンドリングを提供します。成功した値とエラーの両方を表現できる型で、例外を使わずに安全なエラーハンドリングが可能です。Sy Brand(TartanLlama)によって開発され、C++11/14/17で使用できます。monadic操作(map、and_then等)をサポートし、エラーハンドリングロジックを副作用として分離できるため、関数型プログラミングパラダイムと相性が良く、堅牢なコードの作成を支援します。

詳細

tl::expectedは、成功値(T)またはエラー値(E)のいずれかを保持するテンプレートクラスです。std::optionalと似ていますが、値が存在しない場合に詳細なエラー情報を提供できる点が異なります。monadic操作により、エラーハンドリングを関数チェーンから分離し、成功パスに集中したコードを書くことができます。例外を使わないエラーハンドリングパターンにより、パフォーマンスが重要な場面や例外が禁止されている環境でも安全にエラーを処理できます。検証関数と組み合わせることで、強力なバリデーション機能を構築できます。

主な特徴

  • 例外なしエラーハンドリング: 例外を使わずに安全なエラー処理
  • 関数型プログラミング: monadic操作による関数チェーン
  • 型安全性: コンパイル時にエラーハンドリングを強制
  • パフォーマンス: 例外処理のオーバーヘッドがない
  • C++11対応: 古いコンパイラでも使用可能
  • ヘッダーオンリー: 簡単に導入できる

メリット・デメリット

メリット

  • 例外を使わないため、パフォーマンスが予測しやすい
  • エラーハンドリングがコンパイル時に強制される
  • 関数型プログラミングスタイルでクリーンなコード
  • 詳細なエラー情報を型安全に扱える
  • ヘッダーオンリーで導入が簡単
  • C++23標準の先取り実装

デメリット

  • 関数型プログラミングの学習コストが存在
  • 既存の例外ベースコードとの統合に手間
  • デバッグ時のスタックトレースが取得困難
  • 一部の開発者には馴染みがない概念
  • 複雑なエラーハンドリングでは記述が冗長になる可能性

参考ページ

書き方の例

インストールと基本セットアップ

# vcpkgを使用してインストール
vcpkg install tl-expected

# 手動でヘッダーファイルをダウンロード
wget https://github.com/TartanLlama/expected/releases/download/v1.0.0/tl-expected.hpp
# tl-expected.hppを適切なディレクトリに配置

# CMakeでの使用例
find_package(tl-expected REQUIRED)
target_link_libraries(your_target tl::expected)

基本的なエラーハンドリングとバリデーション

#include <tl/expected.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <regex>

// エラー型の定義
enum class ValidationError {
    EMPTY_INPUT,
    INVALID_FORMAT,
    OUT_OF_RANGE,
    INVALID_EMAIL,
    INVALID_PHONE,
    INVALID_URL
};

// エラーメッセージの変換
std::string errorToString(ValidationError error) {
    switch (error) {
        case ValidationError::EMPTY_INPUT:
            return "入力が空です";
        case ValidationError::INVALID_FORMAT:
            return "無効なフォーマットです";
        case ValidationError::OUT_OF_RANGE:
            return "値が範囲外です";
        case ValidationError::INVALID_EMAIL:
            return "無効なメールアドレスです";
        case ValidationError::INVALID_PHONE:
            return "無効な電話番号です";
        case ValidationError::INVALID_URL:
            return "無効なURLです";
        default:
            return "未知のエラー";
    }
}

// 基本的な検証関数
tl::expected<std::string, ValidationError> validateNonEmpty(const std::string& input) {
    if (input.empty()) {
        return tl::unexpected(ValidationError::EMPTY_INPUT);
    }
    return input;
}

tl::expected<std::string, ValidationError> validateLength(const std::string& input, size_t min_len, size_t max_len) {
    if (input.length() < min_len || input.length() > max_len) {
        return tl::unexpected(ValidationError::OUT_OF_RANGE);
    }
    return input;
}

tl::expected<std::string, ValidationError> validateEmail(const std::string& input) {
    static const std::regex email_regex(R"(^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)");
    if (!std::regex_match(input, email_regex)) {
        return tl::unexpected(ValidationError::INVALID_EMAIL);
    }
    return input;
}

tl::expected<std::string, ValidationError> validatePhone(const std::string& input) {
    static const std::regex phone_regex(R"(^(\+81|0)[1-9][0-9]{8,9}$)");
    if (!std::regex_match(input, phone_regex)) {
        return tl::unexpected(ValidationError::INVALID_PHONE);
    }
    return input;
}

tl::expected<int, ValidationError> validateAge(const std::string& input) {
    try {
        int age = std::stoi(input);
        if (age < 0 || age > 120) {
            return tl::unexpected(ValidationError::OUT_OF_RANGE);
        }
        return age;
    } catch (const std::exception&) {
        return tl::unexpected(ValidationError::INVALID_FORMAT);
    }
}

// 数値バリデーション
tl::expected<double, ValidationError> validateNumber(const std::string& input, double min_val, double max_val) {
    try {
        double value = std::stod(input);
        if (value < min_val || value > max_val) {
            return tl::unexpected(ValidationError::OUT_OF_RANGE);
        }
        return value;
    } catch (const std::exception&) {
        return tl::unexpected(ValidationError::INVALID_FORMAT);
    }
}

int main() {
    // 基本的な使用例
    {
        std::cout << "=== 基本的なバリデーション ===" << std::endl;
        
        // 成功ケース
        auto result1 = validateNonEmpty("Hello World");
        if (result1) {
            std::cout << "✓ 成功: " << *result1 << std::endl;
        } else {
            std::cout << "✗ エラー: " << errorToString(result1.error()) << std::endl;
        }
        
        // 失敗ケース
        auto result2 = validateNonEmpty("");
        if (result2) {
            std::cout << "✓ 成功: " << *result2 << std::endl;
        } else {
            std::cout << "✗ エラー: " << errorToString(result2.error()) << std::endl;
        }
    }
    
    // 連続バリデーション
    {
        std::cout << "\n=== 連続バリデーション ===" << std::endl;
        
        std::string email = "[email protected]";
        
        // 関数的な連続バリデーション
        auto result = validateNonEmpty(email)
            .and_then([](const std::string& s) { return validateLength(s, 5, 100); })
            .and_then([](const std::string& s) { return validateEmail(s); });
        
        if (result) {
            std::cout << "✓ メールアドレスは有効です: " << *result << std::endl;
        } else {
            std::cout << "✗ メールアドレスエラー: " << errorToString(result.error()) << std::endl;
        }
    }
    
    // 年齢バリデーション
    {
        std::cout << "\n=== 年齢バリデーション ===" << std::endl;
        
        std::vector<std::string> ages = {"25", "150", "abc", "-5"};
        
        for (const auto& age_str : ages) {
            auto result = validateAge(age_str);
            if (result) {
                std::cout << "✓ 年齢 " << age_str << " は有効です: " << *result << "歳" << std::endl;
            } else {
                std::cout << "✗ 年齢 " << age_str << " は無効です: " << errorToString(result.error()) << std::endl;
            }
        }
    }
    
    // 数値バリデーション
    {
        std::cout << "\n=== 数値バリデーション ===" << std::endl;
        
        std::vector<std::string> numbers = {"3.14", "100.5", "abc", "200"};
        
        for (const auto& num_str : numbers) {
            auto result = validateNumber(num_str, 0.0, 100.0);
            if (result) {
                std::cout << "✓ 数値 " << num_str << " は有効です: " << *result << std::endl;
            } else {
                std::cout << "✗ 数値 " << num_str << " は無効です: " << errorToString(result.error()) << std::endl;
            }
        }
    }
    
    return 0;
}

高度なバリデーション機能と構造化データ

#include <tl/expected.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <regex>

// 複雑なエラー型
struct ValidationError {
    enum Type {
        REQUIRED_FIELD_MISSING,
        INVALID_TYPE,
        INVALID_FORMAT,
        OUT_OF_RANGE,
        INVALID_REFERENCE,
        CUSTOM_ERROR
    };
    
    Type type;
    std::string field;
    std::string message;
    
    ValidationError(Type t, const std::string& f, const std::string& m)
        : type(t), field(f), message(m) {}
    
    std::string toString() const {
        return "フィールド '" + field + "': " + message;
    }
};

// ユーザー情報の構造体
struct UserInfo {
    std::string name;
    std::string email;
    int age;
    std::string phone;
    std::vector<std::string> skills;
    std::map<std::string, std::string> metadata;
    
    UserInfo() = default;
    UserInfo(const std::string& n, const std::string& e, int a, const std::string& p)
        : name(n), email(e), age(a), phone(p) {}
};

// 高度なバリデーション クラス
class UserValidator {
private:
    // 内部バリデーション関数
    static tl::expected<std::string, ValidationError> validateName(const std::string& name) {
        if (name.empty()) {
            return tl::unexpected(ValidationError(ValidationError::REQUIRED_FIELD_MISSING, 
                                                "name", "名前が入力されていません"));
        }
        
        if (name.length() < 2 || name.length() > 50) {
            return tl::unexpected(ValidationError(ValidationError::OUT_OF_RANGE, 
                                                "name", "名前は2文字以上50文字以下である必要があります"));
        }
        
        return name;
    }
    
    static tl::expected<std::string, ValidationError> validateEmailFormat(const std::string& email) {
        if (email.empty()) {
            return tl::unexpected(ValidationError(ValidationError::REQUIRED_FIELD_MISSING, 
                                                "email", "メールアドレスが入力されていません"));
        }
        
        static const std::regex email_regex(R"(^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)");
        if (!std::regex_match(email, email_regex)) {
            return tl::unexpected(ValidationError(ValidationError::INVALID_FORMAT, 
                                                "email", "無効なメールアドレス形式です"));
        }
        
        return email;
    }
    
    static tl::expected<int, ValidationError> validateAgeRange(int age) {
        if (age < 0 || age > 120) {
            return tl::unexpected(ValidationError(ValidationError::OUT_OF_RANGE, 
                                                "age", "年齢は0歳から120歳の範囲で入力してください"));
        }
        
        return age;
    }
    
    static tl::expected<std::string, ValidationError> validatePhoneFormat(const std::string& phone) {
        if (phone.empty()) {
            return phone;  // 電話番号は任意
        }
        
        static const std::regex phone_regex(R"(^(\+81|0)[1-9][0-9]{8,9}$)");
        if (!std::regex_match(phone, phone_regex)) {
            return tl::unexpected(ValidationError(ValidationError::INVALID_FORMAT, 
                                                "phone", "無効な電話番号形式です"));
        }
        
        return phone;
    }
    
    static tl::expected<std::vector<std::string>, ValidationError> validateSkills(const std::vector<std::string>& skills) {
        if (skills.size() > 20) {
            return tl::unexpected(ValidationError(ValidationError::OUT_OF_RANGE, 
                                                "skills", "スキルは20個まで設定できます"));
        }
        
        for (const auto& skill : skills) {
            if (skill.empty()) {
                return tl::unexpected(ValidationError(ValidationError::INVALID_FORMAT, 
                                                    "skills", "空のスキルは設定できません"));
            }
            
            if (skill.length() > 30) {
                return tl::unexpected(ValidationError(ValidationError::OUT_OF_RANGE, 
                                                    "skills", "各スキルは30文字以下である必要があります"));
            }
        }
        
        return skills;
    }

public:
    // 個別フィールドの検証
    static tl::expected<std::string, ValidationError> validateUserName(const std::string& name) {
        return validateName(name);
    }
    
    static tl::expected<std::string, ValidationError> validateUserEmail(const std::string& email) {
        return validateEmailFormat(email);
    }
    
    static tl::expected<int, ValidationError> validateUserAge(int age) {
        return validateAgeRange(age);
    }
    
    static tl::expected<std::string, ValidationError> validateUserPhone(const std::string& phone) {
        return validatePhoneFormat(phone);
    }
    
    // 複合バリデーション
    static tl::expected<UserInfo, ValidationError> validateUser(const UserInfo& user) {
        // 名前の検証
        auto name_result = validateName(user.name);
        if (!name_result) {
            return tl::unexpected(name_result.error());
        }
        
        // メールアドレスの検証
        auto email_result = validateEmailFormat(user.email);
        if (!email_result) {
            return tl::unexpected(email_result.error());
        }
        
        // 年齢の検証
        auto age_result = validateAgeRange(user.age);
        if (!age_result) {
            return tl::unexpected(age_result.error());
        }
        
        // 電話番号の検証
        auto phone_result = validatePhoneFormat(user.phone);
        if (!phone_result) {
            return tl::unexpected(phone_result.error());
        }
        
        // スキルの検証
        auto skills_result = validateSkills(user.skills);
        if (!skills_result) {
            return tl::unexpected(skills_result.error());
        }
        
        // すべて成功した場合
        UserInfo validated_user = user;
        validated_user.name = *name_result;
        validated_user.email = *email_result;
        validated_user.age = *age_result;
        validated_user.phone = *phone_result;
        validated_user.skills = *skills_result;
        
        return validated_user;
    }
    
    // バッチ検証
    static std::vector<tl::expected<UserInfo, ValidationError>> validateUsers(const std::vector<UserInfo>& users) {
        std::vector<tl::expected<UserInfo, ValidationError>> results;
        results.reserve(users.size());
        
        for (const auto& user : users) {
            results.push_back(validateUser(user));
        }
        
        return results;
    }
};

// 条件付きバリデーション
class ConditionalValidator {
public:
    // 年齢に基づく条件付きバリデーション
    static tl::expected<UserInfo, ValidationError> validateUserWithConditions(const UserInfo& user) {
        // 基本バリデーション
        auto basic_result = UserValidator::validateUser(user);
        if (!basic_result) {
            return basic_result;
        }
        
        UserInfo validated_user = *basic_result;
        
        // 条件付きバリデーション
        if (validated_user.age < 18) {
            // 未成年の場合は電話番号が必須
            if (validated_user.phone.empty()) {
                return tl::unexpected(ValidationError(ValidationError::REQUIRED_FIELD_MISSING, 
                                                    "phone", "未成年者は電話番号の入力が必要です"));
            }
        }
        
        if (validated_user.age >= 65) {
            // 高齢者の場合は特別な検証
            if (validated_user.skills.empty()) {
                return tl::unexpected(ValidationError(ValidationError::CUSTOM_ERROR, 
                                                    "skills", "高齢者の方はスキルの入力をお願いします"));
            }
        }
        
        return validated_user;
    }
};

// 実際の使用例
int main() {
    try {
        // 有効なユーザー情報のテスト
        {
            std::cout << "=== 有効なユーザー情報のテスト ===" << std::endl;
            
            UserInfo user("田中太郎", "[email protected]", 30, "09012345678");
            user.skills = {"C++", "Python", "JavaScript"};
            user.metadata = {{"department", "Engineering"}, {"level", "Senior"}};
            
            auto result = UserValidator::validateUser(user);
            if (result) {
                std::cout << "✓ ユーザー情報は有効です:" << std::endl;
                std::cout << "  名前: " << result->name << std::endl;
                std::cout << "  メール: " << result->email << std::endl;
                std::cout << "  年齢: " << result->age << std::endl;
                std::cout << "  電話: " << result->phone << std::endl;
                std::cout << "  スキル数: " << result->skills.size() << std::endl;
            } else {
                std::cout << "✗ " << result.error().toString() << std::endl;
            }
        }
        
        // 無効なユーザー情報のテスト
        {
            std::cout << "\n=== 無効なユーザー情報のテスト ===" << std::endl;
            
            std::vector<UserInfo> invalid_users = {
                {"", "[email protected]", 30, "09012345678"},  // 空の名前
                {"田中太郎", "invalid-email", 30, "09012345678"},  // 無効なメール
                {"田中太郎", "[email protected]", 150, "09012345678"},  // 範囲外の年齢
                {"田中太郎", "[email protected]", 30, "123"},  // 無効な電話番号
            };
            
            auto results = UserValidator::validateUsers(invalid_users);
            
            for (size_t i = 0; i < results.size(); ++i) {
                std::cout << "ユーザー " << (i + 1) << ": ";
                if (results[i]) {
                    std::cout << "✓ 有効" << std::endl;
                } else {
                    std::cout << "✗ " << results[i].error().toString() << std::endl;
                }
            }
        }
        
        // 条件付きバリデーション
        {
            std::cout << "\n=== 条件付きバリデーション ===" << std::endl;
            
            // 未成年のユーザー(電話番号なし)
            UserInfo minor("高校生太郎", "[email protected]", 16, "");
            minor.skills = {"勉強", "部活動"};
            
            auto result = ConditionalValidator::validateUserWithConditions(minor);
            if (result) {
                std::cout << "✓ 未成年ユーザーは有効です" << std::endl;
            } else {
                std::cout << "✗ 未成年ユーザー: " << result.error().toString() << std::endl;
            }
            
            // 高齢者のユーザー(スキルなし)
            UserInfo senior("高齢者花子", "[email protected]", 70, "09087654321");
            
            auto result2 = ConditionalValidator::validateUserWithConditions(senior);
            if (result2) {
                std::cout << "✓ 高齢者ユーザーは有効です" << std::endl;
            } else {
                std::cout << "✗ 高齢者ユーザー: " << result2.error().toString() << std::endl;
            }
        }
        
        // 関数型スタイルの連続バリデーション
        {
            std::cout << "\n=== 関数型スタイルの連続バリデーション ===" << std::endl;
            
            std::string name = "佐藤次郎";
            std::string email = "[email protected]";
            int age = 25;
            std::string phone = "09056781234";
            
            auto final_result = UserValidator::validateUserName(name)
                .and_then([&](const std::string& validated_name) {
                    return UserValidator::validateUserEmail(email)
                        .and_then([&](const std::string& validated_email) {
                            return UserValidator::validateUserAge(age)
                                .and_then([&](int validated_age) {
                                    return UserValidator::validateUserPhone(phone)
                                        .map([&](const std::string& validated_phone) {
                                            return UserInfo(validated_name, validated_email, validated_age, validated_phone);
                                        });
                                });
                        });
                });
            
            if (final_result) {
                std::cout << "✓ 全ての検証が成功しました" << std::endl;
                std::cout << "  構築されたユーザー: " << final_result->name << " (" << final_result->email << ")" << std::endl;
            } else {
                std::cout << "✗ 検証エラー: " << final_result.error().toString() << std::endl;
            }
        }
        
    } catch (const std::exception& e) {
        std::cerr << "予期しないエラー: " << e.what() << std::endl;
    }
    
    return 0;
}

パフォーマンス比較とベンチマーク

#include <tl/expected.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
#include <stdexcept>
#include <random>

// 検証対象のデータ構造
struct TestData {
    std::string value;
    int number;
    
    TestData(const std::string& v, int n) : value(v), number(n) {}
};

// 例外ベースのバリデーション
class ExceptionValidator {
public:
    static TestData validateWithExceptions(const TestData& data) {
        if (data.value.empty()) {
            throw std::invalid_argument("値が空です");
        }
        
        if (data.value.length() < 5 || data.value.length() > 50) {
            throw std::invalid_argument("値の長さが無効です");
        }
        
        if (data.number < 0 || data.number > 1000) {
            throw std::invalid_argument("数値が範囲外です");
        }
        
        return data;
    }
};

// tl::expectedベースのバリデーション
class ExpectedValidator {
public:
    enum class Error {
        EMPTY_VALUE,
        INVALID_LENGTH,
        OUT_OF_RANGE
    };
    
    static tl::expected<TestData, Error> validateWithExpected(const TestData& data) {
        if (data.value.empty()) {
            return tl::unexpected(Error::EMPTY_VALUE);
        }
        
        if (data.value.length() < 5 || data.value.length() > 50) {
            return tl::unexpected(Error::INVALID_LENGTH);
        }
        
        if (data.number < 0 || data.number > 1000) {
            return tl::unexpected(Error::OUT_OF_RANGE);
        }
        
        return data;
    }
};

// テストデータ生成
class TestDataGenerator {
private:
    std::random_device rd;
    std::mt19937 gen{rd()};
    std::uniform_int_distribution<> length_dist{1, 60};
    std::uniform_int_distribution<> char_dist{'a', 'z'};
    std::uniform_int_distribution<> number_dist{-100, 1100};
    std::uniform_real_distribution<> valid_ratio{0.0, 1.0};
    
public:
    std::vector<TestData> generateTestData(size_t count, double valid_percentage = 0.7) {
        std::vector<TestData> data;
        data.reserve(count);
        
        for (size_t i = 0; i < count; ++i) {
            bool should_be_valid = valid_ratio(gen) < valid_percentage;
            
            // 文字列生成
            std::string value;
            if (should_be_valid) {
                int length = std::uniform_int_distribution<>{5, 50}(gen);
                value.reserve(length);
                for (int j = 0; j < length; ++j) {
                    value += static_cast<char>(char_dist(gen));
                }
            } else {
                // 無効なデータを生成
                if (valid_ratio(gen) < 0.3) {
                    value = "";  // 空の文字列
                } else {
                    int length = std::uniform_int_distribution<>{1, 4}(gen);  // 短すぎる
                    value.reserve(length);
                    for (int j = 0; j < length; ++j) {
                        value += static_cast<char>(char_dist(gen));
                    }
                }
            }
            
            // 数値生成
            int number;
            if (should_be_valid) {
                number = std::uniform_int_distribution<>{0, 1000}(gen);
            } else {
                number = number_dist(gen);  // 範囲外の可能性
            }
            
            data.emplace_back(value, number);
        }
        
        return data;
    }
};

// パフォーマンステスト
class PerformanceTest {
public:
    struct BenchmarkResult {
        size_t total_items;
        size_t valid_items;
        size_t invalid_items;
        double elapsed_ms;
        double items_per_second;
        
        void print(const std::string& name) const {
            std::cout << name << " 結果:" << std::endl;
            std::cout << "  総アイテム数: " << total_items << std::endl;
            std::cout << "  有効アイテム数: " << valid_items << std::endl;
            std::cout << "  無効アイテム数: " << invalid_items << std::endl;
            std::cout << "  処理時間: " << elapsed_ms << " ms" << std::endl;
            std::cout << "  処理速度: " << items_per_second << " items/sec" << std::endl;
        }
    };
    
    static BenchmarkResult testExceptionBased(const std::vector<TestData>& test_data) {
        BenchmarkResult result;
        result.total_items = test_data.size();
        result.valid_items = 0;
        result.invalid_items = 0;
        
        auto start = std::chrono::high_resolution_clock::now();
        
        for (const auto& data : test_data) {
            try {
                ExceptionValidator::validateWithExceptions(data);
                result.valid_items++;
            } catch (const std::exception&) {
                result.invalid_items++;
            }
        }
        
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        
        result.elapsed_ms = duration.count() / 1000.0;
        result.items_per_second = (result.total_items * 1000000.0) / duration.count();
        
        return result;
    }
    
    static BenchmarkResult testExpectedBased(const std::vector<TestData>& test_data) {
        BenchmarkResult result;
        result.total_items = test_data.size();
        result.valid_items = 0;
        result.invalid_items = 0;
        
        auto start = std::chrono::high_resolution_clock::now();
        
        for (const auto& data : test_data) {
            auto validation_result = ExpectedValidator::validateWithExpected(data);
            if (validation_result) {
                result.valid_items++;
            } else {
                result.invalid_items++;
            }
        }
        
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        
        result.elapsed_ms = duration.count() / 1000.0;
        result.items_per_second = (result.total_items * 1000000.0) / duration.count();
        
        return result;
    }
};

// 機能的な使用例
class FunctionalExample {
public:
    // 複数のバリデーションを組み合わせる
    static tl::expected<TestData, std::string> validateWithMultipleSteps(const TestData& data) {
        return ExpectedValidator::validateWithExpected(data)
            .map_error([](ExpectedValidator::Error error) {
                switch (error) {
                    case ExpectedValidator::Error::EMPTY_VALUE:
                        return std::string("値が空です");
                    case ExpectedValidator::Error::INVALID_LENGTH:
                        return std::string("値の長さが無効です");
                    case ExpectedValidator::Error::OUT_OF_RANGE:
                        return std::string("数値が範囲外です");
                    default:
                        return std::string("未知のエラー");
                }
            })
            .and_then([](const TestData& validated_data) -> tl::expected<TestData, std::string> {
                // 追加の検証ロジック
                if (validated_data.value.find("invalid") != std::string::npos) {
                    return tl::unexpected(std::string("無効な文字列が含まれています"));
                }
                return validated_data;
            });
    }
    
    // バッチ処理
    static std::vector<tl::expected<TestData, std::string>> validateBatch(const std::vector<TestData>& data) {
        std::vector<tl::expected<TestData, std::string>> results;
        results.reserve(data.size());
        
        for (const auto& item : data) {
            results.push_back(validateWithMultipleSteps(item));
        }
        
        return results;
    }
    
    // 有効なデータのみを抽出
    static std::vector<TestData> extractValidData(const std::vector<TestData>& data) {
        std::vector<TestData> valid_data;
        
        for (const auto& item : data) {
            auto result = validateWithMultipleSteps(item);
            if (result) {
                valid_data.push_back(*result);
            }
        }
        
        return valid_data;
    }
};

int main() {
    try {
        TestDataGenerator generator;
        
        // 小規模テスト
        std::cout << "=== 小規模パフォーマンステスト (10,000 アイテム) ===" << std::endl;
        
        auto small_data = generator.generateTestData(10000, 0.7);
        
        auto exception_result = PerformanceTest::testExceptionBased(small_data);
        exception_result.print("例外ベース");
        
        std::cout << std::endl;
        
        auto expected_result = PerformanceTest::testExpectedBased(small_data);
        expected_result.print("tl::expected ベース");
        
        double speedup = expected_result.items_per_second / exception_result.items_per_second;
        std::cout << "\n速度向上: " << speedup << "x" << std::endl;
        
        // 大規模テスト
        std::cout << "\n=== 大規模パフォーマンステスト (100,000 アイテム) ===" << std::endl;
        
        auto large_data = generator.generateTestData(100000, 0.7);
        
        auto large_exception_result = PerformanceTest::testExceptionBased(large_data);
        large_exception_result.print("例外ベース");
        
        std::cout << std::endl;
        
        auto large_expected_result = PerformanceTest::testExpectedBased(large_data);
        large_expected_result.print("tl::expected ベース");
        
        double large_speedup = large_expected_result.items_per_second / large_exception_result.items_per_second;
        std::cout << "\n速度向上: " << large_speedup << "x" << std::endl;
        
        // 機能的な使用例
        std::cout << "\n=== 機能的な使用例 ===" << std::endl;
        
        auto sample_data = generator.generateTestData(10, 0.5);
        auto functional_results = FunctionalExample::validateBatch(sample_data);
        
        std::cout << "バッチ処理結果:" << std::endl;
        for (size_t i = 0; i < functional_results.size(); ++i) {
            const auto& result = functional_results[i];
            std::cout << "  アイテム " << (i + 1) << ": ";
            if (result) {
                std::cout << "✓ 有効 (値: " << result->value.substr(0, 10) << "..., 数値: " << result->number << ")" << std::endl;
            } else {
                std::cout << "✗ エラー: " << result.error() << std::endl;
            }
        }
        
        // 有効なデータのみ抽出
        auto valid_data = FunctionalExample::extractValidData(sample_data);
        std::cout << "\n有効なデータのみ抽出: " << valid_data.size() << " / " << sample_data.size() << " アイテム" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "エラー: " << e.what() << std::endl;
    }
    
    return 0;
}