shogo-library

競技プログラミング用の C++ ライブラリ

View the Project on GitHub shogo314/shogo-library

:heavy_check_mark: test/unittest/macro.test.cpp

Depends on

Code

#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// macro.hpp のマクロの動作を検証する
// 入力マクロは std::cin の入力元を、出力マクロは std::cout の出力先を一時的に差し替えて検証する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include "../../src/base/macro.hpp"

bool ok = true;
void check(bool cond, const char* what) {
    if (!cond) {
        if (ok) std::cerr << "failed: " << what << std::endl;
        ok = false;
    }
}

// for 文で愚直に作った列
std::vector<ll> naive_up(ll a, ll n, ll t) {
    std::vector<ll> v;
    for (ll i = a; i < n; i += t) v.push_back(i);
    return v;
}
std::vector<ll> naive_down(ll a, ll n, ll t) {
    std::vector<ll> v;
    for (ll i = n - 1; i >= a; i -= t) v.push_back(i);
    return v;
}

// 出力マクロは return するので void 関数の中で使う
// after が書き換わらなければ、マクロの後ろは実行されていない
int after = 0;
void yes_upper() { YES after = 1; }
void no_upper() { NO after = 1; }
void yes_lower() { Yes after = 1; }
void no_lower() { No after = 1; }
void takahashi() { Takahashi after = 1; }
void aoki() { Aoki after = 1; }

template <class F>
std::string capture_cout(F f) {
    std::ostringstream buf;
    std::streambuf* old = std::cout.rdbuf(buf.rdbuf());
    f();
    std::cout.rdbuf(old);
    return buf.str();
}

int calls = 0;
ll counted(ll x) {
    calls++;
    return x;
}

int main() {
    // all
    {
        std::vector<int> v{3, 1, 2};
        std::sort(all(v));
        check(v == std::vector<int>({1, 2, 3}), "all");
    }

    // rep (1〜4 引数)
    for (ll a = -3; a <= 6; a++) {
        for (ll n = -3; n <= 8; n++) {
            {
                int cnt = 0;
                rep(n) cnt++;
                check(cnt == std::max<ll>(n, 0), "rep(n)");
            }
            {
                std::vector<ll> v;
                rep(i, n) v.push_back(i);
                check(v == naive_up(0, n, 1), "rep(i, n)");
            }
            {
                std::vector<ll> v;
                rep(i, a, n) v.push_back(i);
                check(v == naive_up(a, n, 1), "rep(i, a, n)");
            }
            for (ll t = 1; t <= 4; t++) {
                std::vector<ll> v;
                rep(i, a, n, t) v.push_back(i);
                check(v == naive_up(a, n, t), "rep(i, a, n, t)");
            }
            {
                std::vector<ll> v;
                repd(i, n) v.push_back(i);
                check(v == naive_down(0, n, 1), "repd(i, n)");
            }
            {
                std::vector<ll> v;
                repd(i, a, n) v.push_back(i);
                check(v == naive_down(a, n, 1), "repd(i, a, n)");
            }
            for (ll t = 1; t <= 4; t++) {
                std::vector<ll> v;
                repd(i, a, n, t) v.push_back(i);
                check(v == naive_down(a, n, t), "repd(i, a, n, t)");
            }
        }
        {
            std::vector<ll> v;
            rrep(i, a) v.push_back(i);
            check(v == naive_up(1, a + 1, 1), "rrep(i, n)");
        }
        {
            std::vector<ll> v;
            rrepd(i, a) v.push_back(i);
            check(v == naive_down(1, a + 1, 1), "rrepd(i, n)");
        }
    }
    {
        // rep(n) を同じスコープで入れ子にできる (ループ変数の名前が重ならない)
        int cnt = 0;
        rep(3) rep(4) cnt++;
        check(cnt == 12, "nested rep(n)");
        // 終端と増分は最初に 1 回だけ評価される
        calls = 0;
        int iter = 0;
        rep(i, 0, counted(5), counted(2)) iter++;
        check(iter == 3 && calls == 2, "rep evaluates bounds once");
        // ループ変数は long long
        rep(i, 1) static_assert(std::is_same_v<decltype(i), long long>);
    }

    // 入力マクロ
    {
        std::istringstream in(
            "1 -2 "            // LL(a, b)
            "hello world "     // STR(s, t)
            "7 "               // IN(int, x)
            "z "               // CHAR(c)
            "3 4 5 "           // VL(v, 3)
            "6 7 "             // AL(arr, 2)
            "1 2 3 4 5 6 "     // AAL(aa, 2, 3)
            "x y "             // VC(vc_, 2)
            "ab cd "           // VS(vs_, 2)
            "1 2 3 4 "         // VPL(vp, 2)
            "1 2 3 4 5 6 "     // VAL(va, 2, 3)
            "9 8 7 6 "         // VVL(vv_, 2, 2)
            "5 3 5 1 ");       // SL(st, 4)
        std::streambuf* old = std::cin.rdbuf(in.rdbuf());
        LL(a, b);
        STR(s, t);
        IN(int, x);
        CHAR(c);
        VL(v, 3);
        AL(arr, 2);
        AAL(aa, 2, 3);
        VC(vc_, 2);
        VS(vs_, 2);
        VPL(vp, 2);
        VAL(va, 2, 3);
        VVL(vv_, 2, 2);
        SL(st, 4);
        std::cin.rdbuf(old);
        check(a == 1 && b == -2 && std::is_same_v<decltype(a), ll>, "LL");
        check(s == "hello" && t == "world", "STR");
        check(x == 7 && std::is_same_v<decltype(x), int>, "IN");
        check(c == 'z', "CHAR");
        check(v == vl({3, 4, 5}), "VL");
        check(arr == al<2>{6, 7}, "AL");
        check(aa == aal<2, 3>{{{1, 2, 3}, {4, 5, 6}}}, "AAL");
        check(vc_ == vc({'x', 'y'}), "VC");
        check(vs_ == vs({"ab", "cd"}), "VS");
        check(vp == vpl({{1, 2}, {3, 4}}), "VPL");
        check(va == val<3>({{1, 2, 3}, {4, 5, 6}}), "VAL");
        check(vv_ == vvl({{9, 8}, {7, 6}}), "VVL");
        check(st == sl({1, 3, 5}), "SL");
        check(bool(in), "input stream state");
    }
    {
        // scan を直接使う
        std::istringstream in("10 abc 2.5");
        std::streambuf* old = std::cin.rdbuf(in.rdbuf());
        int p;
        std::string q;
        double r;
        scan(p, q, r);
        scan();
        std::cin.rdbuf(old);
        check(p == 10 && q == "abc" && r == 2.5, "scan");
    }

    // 出力マクロ (出力して return する)
    after = 0;
    check(capture_cout(yes_upper) == "YES\n", "YES");
    check(capture_cout(no_upper) == "NO\n", "NO");
    check(capture_cout(yes_lower) == "Yes\n", "Yes");
    check(capture_cout(no_lower) == "No\n", "No");
    check(capture_cout(takahashi) == "Takahashi\n", "Takahashi");
    check(capture_cout(aoki) == "Aoki\n", "Aoki");
    check(after == 0, "output macros return");

    if (ok) std::cout << "Hello World" << std::endl;
}
#line 1 "test/unittest/macro.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// macro.hpp のマクロの動作を検証する
// 入力マクロは std::cin の入力元を、出力マクロは std::cout の出力先を一時的に差し替えて検証する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#line 2 "src/base/macro.hpp"

/**
 * @file macro.hpp
 * @brief マクロ (rep など)
 */

#line 2 "src/base/io.hpp"
/**
 * @file io.hpp
 * @brief 空白区切り出力、iostreamのオーバーロード
 */

#include <array>
#line 9 "src/base/io.hpp"
#include <set>
#include <utility>
#include <tuple>
#line 13 "src/base/io.hpp"

// ネストした型 (pair<vector<int>, int> など) を扱えるように先に宣言しておく
template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::pair<T1, T2>& p);
template <typename... Types, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::tuple<Types...>& p);
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::array<T, N>& a);
template <typename T, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::vector<T>& v);
template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::pair<T1, T2>& p);
template <typename... Types, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::tuple<Types...>& p);
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::array<T, N>& a);
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::vector<T>& v);
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::set<T>& s);

namespace tuple_io {
    template <typename Tuple, size_t I, typename CharT, typename Traits>
    std::basic_istream<CharT, Traits>& read_tuple(std::basic_istream<CharT, Traits>& is, Tuple& t) {
        is >> std::get<I>(t);
        if constexpr (I + 1 < std::tuple_size_v<Tuple>) {
            return read_tuple<Tuple, I + 1>(is, t);
        }
        return is;
    }
    template <typename Tuple, size_t I, typename CharT, typename Traits>
    std::basic_ostream<CharT, Traits>& write_tuple(std::basic_ostream<CharT, Traits>& os, const Tuple& t) {
        os << std::get<I>(t);
        if constexpr (I + 1 < std::tuple_size_v<Tuple>) {
            os << CharT(' ');
            return write_tuple<Tuple, I + 1>(os, t);
        }
        return os;
    }
};

template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::pair<T1, T2>& p) {
    is >> p.first >> p.second;
    return is;
}
template <typename... Types, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::tuple<Types...>& p) {
    return tuple_io::read_tuple<std::tuple<Types...>, 0>(is, p);
}
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::array<T, N>& a) {
    for(auto& e : a) is >> e;
    return is;
}
template <typename T, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::vector<T>& v) {
    for(auto& e : v) is >> e;
    return is;
}

template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::pair<T1, T2>& p) {
    os << p.first << CharT(' ') << p.second;
    return os;
}
template <typename... Types, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::tuple<Types...>& p) {
    return tuple_io::write_tuple<std::tuple<Types...>, 0>(os, p);
}
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::array<T, N>& a) {
    for(size_t i = 0; i < N; ++i) {
        if(i) os << CharT(' ');
        os << a[i];
    }
    return os;
}
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::vector<T>& v) {
    for(size_t i = 0; i < v.size(); ++i) {
        if(i) os << CharT(' ');
        os << v[i];
    }
    return os;
}
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::set<T>& s) {
    for(auto itr = s.begin(); itr != s.end(); ++itr) {
        if(itr != s.begin()) os << CharT(' ');
        os << *itr;
    }
    return os;
}

/**
 * @brief 空行出力
 */
inline void print() { std::cout << '\n'; }
/**
 * @brief 出力して改行
 * 
 * @tparam T 型
 * @param x 出力する値
 */
template <typename T>
void print(const T& x) { std::cout << x << '\n'; }
/**
 * @brief 空白区切りで出力して改行
 * 
 * @tparam T 1つ目の要素の型
 * @tparam Tail 2つ目以降の要素の型
 * @param x 1つ目の要素
 * @param tail 2つ目以降の要素
 */
template <typename T, typename... Tail>
void print(const T& x, const Tail&... tail) {
    std::cout << x << ' ';
    print(tail...);
}

/**
 * @brief 標準エラー出力に空行出力
 */
inline void err() { std::cerr << std::endl; }
/**
 * @brief 標準エラー出力に出力して改行
 *
 * @tparam T 型
 * @param x 出力する値
 */
template <typename T>
void err(const T& x) { std::cerr << x << std::endl; }
/**
 * @brief 標準エラー出力に空白区切りで出力して改行
 *
 * @tparam T 1つ目の要素の型
 * @tparam Tail 2つ目以降の要素の型
 * @param x 1つ目の要素
 * @param tail 2つ目以降の要素
 */
template <typename T, typename... Tail>
void err(const T& x, const Tail&... tail) {
    std::cerr << x << ' ';
    err(tail...);
}
#line 2 "src/base/type_alias.hpp"

/**
 * @file type_alias.hpp
 * @brief 型の別名
 */

#include <bits/stdc++.h>

using ll = long long;
using ull = unsigned long long;
using ld = long double;

template <typename T>
using vec = std::vector<T>;
template <typename T, int N>
using ary = std::array<T, N>;
using str = std::string;
using std::deque;
using std::list;
using std::map;
using std::multimap;
using std::multiset;
using std::pair;
using std::set;

using pl = pair<ll, ll>;
using pd = pair<ld, ld>;

template <typename T>
using vv = vec<vec<T>>;
template <typename T>
using vvv = vec<vec<vec<T>>>;
using vl = vec<ll>;
using vvl = vv<ll>;
using vvvl = vvv<ll>;
using vs = vec<str>;
using vc = vec<char>;
using vi = vec<int>;
using vb = vec<bool>;

template <typename T1, typename T2>
using vp = vec<pair<T1, T2>>;
using vpl = vec<pl>;
using vvpl = vv<pl>;
using vd = vec<ld>;
using vpd = vec<pd>;

template <int N>
using al = ary<ll, N>;
template <int N1, int N2>
using aal = ary<ary<ll, N2>, N1>;
template <int N>
using val = vec<al<N>>;
template <int N>
using avl = ary<vl,N>;

template <typename T>
using ml = std::map<ll, T>;
using mll = std::map<ll, ll>;
using sl = std::set<ll>;
using spl = set<pl>;
template <int N>
using sal = set<al<N>>;
template <int N>
using asl = ary<sl,N>;

template <typename T>
using heap_max = std::priority_queue<T, std::vector<T>, std::less<T>>;
template <typename T>
using heap_min = std::priority_queue<T, std::vector<T>, std::greater<T>>;
#line 10 "src/base/macro.hpp"

#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define all(obj) (obj).begin(), (obj).end()

#define CONCAT_IMPL2(x, y) x##y
#define CONCAT_IMPL(x, y) CONCAT_IMPL2(x, y)
#define UNIQUE_ID(base) CONCAT_IMPL(base, __COUNTER__)

#define GET_MACRO(_1, _2, _3, _4, NAME, ...) NAME

#define rep4(i, a, n, t) for (long long i = static_cast<long long>(a), i##_loop_end = static_cast<long long>(n), i##_loop_step = static_cast<long long>(t); i < i##_loop_end; i += i##_loop_step)
#define rep3(i, a, n) for (long long i = static_cast<long long>(a), i##_loop_end = static_cast<long long>(n); i < i##_loop_end; ++i)
#define rep2(i, n) rep3(i, 0, n)
#define rep1(n) rep2(UNIQUE_ID(loop_counter_), n)
#define rep(...) GET_MACRO(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)

#define repd4(i, a, n, t) for (long long i = static_cast<long long>(n) - 1, i##_loop_end = static_cast<long long>(a), i##_loop_step = static_cast<long long>(t); i >= i##_loop_end; i -= i##_loop_step)
#define repd3(i, a, n) for (long long i = static_cast<long long>(n) - 1, i##_loop_end = static_cast<long long>(a); i >= i##_loop_end; --i)
#define repd2(i, n) repd3(i, 0, n)
#define repd(...) GET_MACRO(__VA_ARGS__, repd4, repd3, repd2)(__VA_ARGS__)

#define rrep(i, n) rep(i, 1, (n) + 1)
#define rrepd(i, n) repd(i, 1, (n) + 1)

inline void scan(){}
template<class Head,class... Tail>
inline void scan(Head&head,Tail&... tail){std::cin>>head;scan(tail...);}
#define LL(...) ll __VA_ARGS__;scan(__VA_ARGS__)
#define STR(...) str __VA_ARGS__;scan(__VA_ARGS__)
#define IN(a, x) a x; std::cin >> x;
#define CHAR(x) char x; std::cin >> x;
#define VL(a,n) vl a(n); std::cin >> a;
#define AL(a,k) al<k> a; std::cin >> a;
#define AAL(a,n,m) aal<n,m> a; std::cin >> a;
#define VC(a,n) vc a(n); std::cin >> a;
#define VS(a,n) vs a(n); std::cin >> a;
#define VPL(a,n) vpl a(n); std::cin >> a;
#define VAL(a,n,k) val<k> a(n); std::cin >> a;
#define VVL(a,n,m) vvl a(n,vl(m)); std::cin >> a;
#define SL(a,n) sl a;{VL(b,n);a=sl(all(b));}

#define NO std::cout << "NO" << std::endl; return;
#define YES std::cout << "YES" << std::endl; return;
#define No std::cout << "No" << std::endl; return;
#define Yes std::cout << "Yes" << std::endl; return;
#define Takahashi std::cout << "Takahashi" << std::endl; return;
#define Aoki std::cout << "Aoki" << std::endl; return;
#line 13 "test/unittest/macro.test.cpp"

bool ok = true;
void check(bool cond, const char* what) {
    if (!cond) {
        if (ok) std::cerr << "failed: " << what << std::endl;
        ok = false;
    }
}

// for 文で愚直に作った列
std::vector<ll> naive_up(ll a, ll n, ll t) {
    std::vector<ll> v;
    for (ll i = a; i < n; i += t) v.push_back(i);
    return v;
}
std::vector<ll> naive_down(ll a, ll n, ll t) {
    std::vector<ll> v;
    for (ll i = n - 1; i >= a; i -= t) v.push_back(i);
    return v;
}

// 出力マクロは return するので void 関数の中で使う
// after が書き換わらなければ、マクロの後ろは実行されていない
int after = 0;
void yes_upper() { YES after = 1; }
void no_upper() { NO after = 1; }
void yes_lower() { Yes after = 1; }
void no_lower() { No after = 1; }
void takahashi() { Takahashi after = 1; }
void aoki() { Aoki after = 1; }

template <class F>
std::string capture_cout(F f) {
    std::ostringstream buf;
    std::streambuf* old = std::cout.rdbuf(buf.rdbuf());
    f();
    std::cout.rdbuf(old);
    return buf.str();
}

int calls = 0;
ll counted(ll x) {
    calls++;
    return x;
}

int main() {
    // all
    {
        std::vector<int> v{3, 1, 2};
        std::sort(all(v));
        check(v == std::vector<int>({1, 2, 3}), "all");
    }

    // rep (1〜4 引数)
    for (ll a = -3; a <= 6; a++) {
        for (ll n = -3; n <= 8; n++) {
            {
                int cnt = 0;
                rep(n) cnt++;
                check(cnt == std::max<ll>(n, 0), "rep(n)");
            }
            {
                std::vector<ll> v;
                rep(i, n) v.push_back(i);
                check(v == naive_up(0, n, 1), "rep(i, n)");
            }
            {
                std::vector<ll> v;
                rep(i, a, n) v.push_back(i);
                check(v == naive_up(a, n, 1), "rep(i, a, n)");
            }
            for (ll t = 1; t <= 4; t++) {
                std::vector<ll> v;
                rep(i, a, n, t) v.push_back(i);
                check(v == naive_up(a, n, t), "rep(i, a, n, t)");
            }
            {
                std::vector<ll> v;
                repd(i, n) v.push_back(i);
                check(v == naive_down(0, n, 1), "repd(i, n)");
            }
            {
                std::vector<ll> v;
                repd(i, a, n) v.push_back(i);
                check(v == naive_down(a, n, 1), "repd(i, a, n)");
            }
            for (ll t = 1; t <= 4; t++) {
                std::vector<ll> v;
                repd(i, a, n, t) v.push_back(i);
                check(v == naive_down(a, n, t), "repd(i, a, n, t)");
            }
        }
        {
            std::vector<ll> v;
            rrep(i, a) v.push_back(i);
            check(v == naive_up(1, a + 1, 1), "rrep(i, n)");
        }
        {
            std::vector<ll> v;
            rrepd(i, a) v.push_back(i);
            check(v == naive_down(1, a + 1, 1), "rrepd(i, n)");
        }
    }
    {
        // rep(n) を同じスコープで入れ子にできる (ループ変数の名前が重ならない)
        int cnt = 0;
        rep(3) rep(4) cnt++;
        check(cnt == 12, "nested rep(n)");
        // 終端と増分は最初に 1 回だけ評価される
        calls = 0;
        int iter = 0;
        rep(i, 0, counted(5), counted(2)) iter++;
        check(iter == 3 && calls == 2, "rep evaluates bounds once");
        // ループ変数は long long
        rep(i, 1) static_assert(std::is_same_v<decltype(i), long long>);
    }

    // 入力マクロ
    {
        std::istringstream in(
            "1 -2 "            // LL(a, b)
            "hello world "     // STR(s, t)
            "7 "               // IN(int, x)
            "z "               // CHAR(c)
            "3 4 5 "           // VL(v, 3)
            "6 7 "             // AL(arr, 2)
            "1 2 3 4 5 6 "     // AAL(aa, 2, 3)
            "x y "             // VC(vc_, 2)
            "ab cd "           // VS(vs_, 2)
            "1 2 3 4 "         // VPL(vp, 2)
            "1 2 3 4 5 6 "     // VAL(va, 2, 3)
            "9 8 7 6 "         // VVL(vv_, 2, 2)
            "5 3 5 1 ");       // SL(st, 4)
        std::streambuf* old = std::cin.rdbuf(in.rdbuf());
        LL(a, b);
        STR(s, t);
        IN(int, x);
        CHAR(c);
        VL(v, 3);
        AL(arr, 2);
        AAL(aa, 2, 3);
        VC(vc_, 2);
        VS(vs_, 2);
        VPL(vp, 2);
        VAL(va, 2, 3);
        VVL(vv_, 2, 2);
        SL(st, 4);
        std::cin.rdbuf(old);
        check(a == 1 && b == -2 && std::is_same_v<decltype(a), ll>, "LL");
        check(s == "hello" && t == "world", "STR");
        check(x == 7 && std::is_same_v<decltype(x), int>, "IN");
        check(c == 'z', "CHAR");
        check(v == vl({3, 4, 5}), "VL");
        check(arr == al<2>{6, 7}, "AL");
        check(aa == aal<2, 3>{{{1, 2, 3}, {4, 5, 6}}}, "AAL");
        check(vc_ == vc({'x', 'y'}), "VC");
        check(vs_ == vs({"ab", "cd"}), "VS");
        check(vp == vpl({{1, 2}, {3, 4}}), "VPL");
        check(va == val<3>({{1, 2, 3}, {4, 5, 6}}), "VAL");
        check(vv_ == vvl({{9, 8}, {7, 6}}), "VVL");
        check(st == sl({1, 3, 5}), "SL");
        check(bool(in), "input stream state");
    }
    {
        // scan を直接使う
        std::istringstream in("10 abc 2.5");
        std::streambuf* old = std::cin.rdbuf(in.rdbuf());
        int p;
        std::string q;
        double r;
        scan(p, q, r);
        scan();
        std::cin.rdbuf(old);
        check(p == 10 && q == "abc" && r == 2.5, "scan");
    }

    // 出力マクロ (出力して return する)
    after = 0;
    check(capture_cout(yes_upper) == "YES\n", "YES");
    check(capture_cout(no_upper) == "NO\n", "NO");
    check(capture_cout(yes_lower) == "Yes\n", "Yes");
    check(capture_cout(no_lower) == "No\n", "No");
    check(capture_cout(takahashi) == "Takahashi\n", "Takahashi");
    check(capture_cout(aoki) == "Aoki\n", "Aoki");
    check(after == 0, "output macros return");

    if (ok) std::cout << "Hello World" << std::endl;
}
Back to top page