な〜にがStrongTypedefじゃ

この記事はC++ Advent Calendar 201220日目の記事です.

導入

ある型に別名を付けるtypedefに対して,ある型を元に新しい型を作る機能をstrong typedefと言います.もちろんC++の仕様としてそのようなものがあるわけではなく,Boost.Serializationにマクロとして実装されているほか,同様のマクロによる実装がいくつかあります.

なぜこのようなものが必要かという話ですが,世の中にはグーグル=センセイという実際博識なセンセイがいらっしゃいますので,氏にお尋ねいただくのがよろしいかと思います.

ところで,Boost.Serializationにあるstrong typedefには制限があり,適用範囲が組み込み型に限られるのです.その他の実装でも,元となる型との間で暗黙変換を許可する/しないを指定する術がなく,実装によって決められてしまいます(知ってる限りの実装においては).私は変換だけでなく,ありとあらゆる元の型のメンバについて公開する,しないの指定をしたいと思いました.

思ったので作りました.

できました.ここにあります.

https://github.com/dechimal/desalt/

おおざっぱな機能の紹介

はじめに

以下のコードは全て

#include <vector>
#include <iostream>
#include <desalt/newtype.hpp>

があるものとします.

最小の定義

試しにvectorを元に新しい型を作ります.

DESALT_NEWTYPE(ivector, std::vector<int>,
    as_base
);

これでstd::vectorを元にivectorという新しい型を定義しました.この型には次の操作ができます.

  • std::vectorからivectorの新しいオブジェクトを作る
  • コピーする
  • ivectorオブジェクトをas_baseメンバ関数によって明示的にvectorとして扱えるようにする
  • 破棄する
元のクラスのメンバをそのまま使う

これだけやったら別にマクロいらんやろ!!!と思ったので,もっと機能を付け足しました.

DESALT_NEWTYPE(ivector, std::vector<int>,
    as_base,
    begin,
    end
);

これでbeginとendが呼べるようになりました.本当ですか?試してみましょう.

int main() {
    ivector iv(std::vector<int>{1,2,3});
    for (auto i : iv) {
        std::cout << i << '\n';
    }
    std::vector<int> & v = iv.as_base();
}

range based for使うために必要なものは,iteratorを返すbeginとendです.もしこれがコンパイルできないなら,今すぐそのようなザコなコンパイラは捨てましょう.

コンストラクタもそのまま使う

上のマクロを見れば分かるように,メンバの名前を書けば,元のクラスのメンバを呼び出せるようになります.ところで,やはり元のクラスのコンストラクタもそのまま使いたいと思うこともあるでしょう.やりましょう.

DESALT_NEWTYPE(ivector, std::vector<int>,
    as_base,
    begin,
    end,
    this
);

int main() {
     ivector iv1{1,2,3};
     ivector iv2(iv1.begin(), iv2.end());
}

this とだけ書けばstd::vectorの全てのコンストラクタがivectorでも余裕のよっちゃんで使えるようになります.

テンプレート

ところでさいきんtemplate aliasesってのがあるじゃないですか.template using vec = std::vector; みたいなの.これみたいにtemplateに対しても別名宣言できたりは…するんですねこれが.

template<typename T>
DESALT_NEWTYPE(dynamic_array, std::vector<T>,
    as_base,
    begin,
    end,
    this
);

int main() {
    dynamic_array<int> di{1,2,3};
    for (auto i : di) {
        std::cout << i << '\n';
    }
}
手動で機能を追加する

最後の手段として,自分で勝手にメンバとかを付け加えたりもできます.

template<typename T>
DESALT_NEWTYPE(dynamic_array, std::vector<T>,
    as_base,
    begin,
    end,
    this,
    new (
        void f() const { std::cout << "hoge\n"; }
    )
);

int main() {
    dynamic_array<int> di{1,2,3};
    for (auto i : di) {
        std::cout << i << '\n';
    }
    di.f();
}
その他

で,本当なら他にも機能あったんですが,まだほとんどの場合正しく動かないので使えません(実装を読んで挙動を理解できるなら使ってもよい).

書式

DESALT_NEWTYPE(identifier, underlying_type, convert_to_base_function_name);
DESALT_NEWTYPE(identifier, underlying_type, convert_to_base_function_name, ...);
  • identifier : 新しい型の名前
  • underlying_type : 元になる型の名前
  • converto_to_base_function_name : 元の型の値を取り出す用の関数の名前

... は以下の要素のどれかをカンマで区切って並べたN個の列 (N ≦ 64)

this // using underlying_type::underlying_type;
member_name // using underlying_type::member_name;
friend function_name // friend function_name;
friend class class_name // friend class class_name;
typename type // using typename underlying_type::type;
new ( ... ) // ... をそのまま定義に付け加える

Boost.Preprocessor の可変長マクロ引数対応

これはBoost Advent Calendar 2011の5日目の記事です。

さて、Boostも徐々にC++11対応が進んでいまして、その中には当然、Boost内で最も利用されている、超有名かつ超重要、某社のサーバでも利用されているという純粋関数型言語C/C++プリプロセッサ用拡張ライブラリBoost.Preprocessorも入っているわけです。そこで今回はそのBoost.PPのC++11対応についてのお話をしたいと思います。

C++11におけるプリプロセッサの新機能といえばなんと言っても可変長マクロ引数、これしかありません。念のために例を示しますと、

#define ROTATE(...) ROTATE_I(__VA_ARGS__)
#define ROTATE_I(x, ...) __VA_ARGS__, x

ROTATE(1, 2) // 2, 1
ROTATE(ROTATE(1, 2, 3)) // 3, 1, 2

というように、関数形式のマクロで任意個の引数を取ることができるようになる機能です。詳しくはC++11 Advent Calendar 2011 4で書きます(BoostではなくC++11であることに注意、この記事が最初に公開された時点ではなぜか存在しません)。完璧な流れですね。

さてここからが本題です。Boost.PPの可変長マクロ引数への対応としては、タプル操作系の関数形式マクロの機能拡張と、新しい関数形式マクロがあります(なお、ここではプリプロセッサの話しかしないので、今後はいちいち「関数形式マクロ」と言わず単に「関数」と言います)。
まずはタプル操作系関数から紹介します。

タプル操作系関数の機能拡張

機能拡張の説明の前にひとつ。普段から実務でプリプロセッサを使っていらっしゃるみなさまにそんな野暮な説明など不要であるとは思いますが、念のためごく簡単に申し上げておきますと、Boost.PPで言う「タプル」とは、バランスの取れたカッコで囲まれたカンマ区切りのトークン列です。
拡張されたタプル操作関数は、操作対象のタプルの長さを与えてやる必要がなくなりました。BOOST_PP_TUPLE_ELEMを例にとって見てみます。

// (a, b, c) の1要素目(つまりb)を取得する
BOOST_PP_TUPLE_ELEM(3, 1, (a, b, c)) // 可変長マクロ引数のサポート無し
BOOST_PP_TUPLE_ELEM(1, (a, b, c))    // サポート有り

サポート無し版の最初の引数が要素数です。タプルの長さを書く必要がなくなりました。なお、サポートが有る場合であっても、依然として長さを与えることもでき、その場合はサポート無しのときと同様に振る舞います。つまり長さが合っていないと実行中にエラーとなります。
なお、いくつかのタプル操作関数は「F(size) tuple」という形式を持ちますが、これらの関数では「F() tuple」という形式でサポートされます。以下、例です。

TUPLE_EAT(3) (a, b, c)
TUPLE_EAT() (a, b, c)

追加された関数

実のところタプル操作系関数の拡張部分は、この追加された関数を利用して実装されています。ここでは主要な関数について説明していきます。

BOOST_PP_VARIADIC_ELEM(i, ...)

この関数は、最初の引数を除いた引数全体の展開後のトークン列から、i番目の引数を取得する関数です。ただし実装の都合上、iは64未満です。

BOOST_PP_VARIADIC_ELEM(1, a, b, c) // b

#define ARGS1 a, b
#define ARGS2 , c, d, e
BOOST_PP_VARIADIC_ELEM(3, ARGS1 ARGS2) // d

この関数には注意があり、GCCとClangでは-pedantic-errorsを付けないと

BOOST_PP_VARIADIC_ELEM(0)
BOOST_PP_VARIADIC_ELEM(1,)
BOOST_PP_VARIADIC_ELEM(2,,)
…

は全てvalidとなってしまいます。これは、GCCのデフォルトでは

#define F(a, ...)

なるFについて、

F(x)

を許すことに由来する挙動です(規格では許されていません)。VCやその他のコンパイラプリプロセッサではどうなのか知りませんが、ご存知の方がいれば教えてください。
なお、これはその他の可変長マクロ引数に対応している関数全体についても言えます。

BOOST_PP_VARIADIC_SIZE(...)

...を全て展開した後のトークン列に対して、カンマ区切りの要素数を数える関数です。

BOOST_PP_VARIADIC_SIZE(a, b, c) // 3
BOOST_PP_VARIADIC_SIZE(,,,,) // 5

この関数にも注意があり、

BOOST_PP_VARIADIC_SIZE()

は1です。これについてはC++11 Advent Calendar 4を参照してください。

BOOST_PP_VARIADIC_TO_*(...)

以下の4つの関数

  • BOOST_PP_VARIADIC_TO_ARRAY
  • BOOST_PP_VARIADIC_TO_LIST
  • BOOST_PP_VARIADIC_TO_SEQ
  • BOOST_PP_VARIADIC_TO_TUPLE

は、...を展開してできたカンマ区切りトークン列を、名前にある通りのデータ構造を持つトークン列に変換する関数です。釈迦に説法ではございますが念のために例を挙げますと、

BOOST_PP_VARIADIC_TO_ARRAY(a, b, c) // (3, (a, b, c))
BOOST_PP_VARIADIC_TO_LIST(a, b, c) // (a, (b, (c, BOOST_PP_NIL)))
BOOST_PP_VARIADIC_TO_SEQ(a, b, c) // (a)(b)(c)
BOOST_PP_VARIADIC_TO_TUPLE(a, b, c) // (a, b, c)

となります。
これらの関数でも、0引数での呼び出し(例:BOOST_PP_ARRAY()など)では0要素目が空トークン列である1要素の各構造を持つトークン列を作ります。

BOOST_PP_OVERLOAD

この関数は、引数の数によって関数を擬似的にオーバーロードするための関数です。あるいは引数の数に応じて別の関数へとディスパッチするための関数と言ったほうが分かりやすいと思う方もいらっしゃるでしょう。次の例は、引数を全てトークン連結する関数です。

#define CAT(...) BOOST_PP_OVERLOAD(CAT_, __VA_ARGS__)(__VA_ARGS__)

#define CAT_1(a0) a0
#define CAT_2(a0, a1) BOOST_PP_CAT(a0, CAT_1(a1))
#define CAT_3(a0, a1, a2) BOOST_PP_CAT(a0, CAT_2(a1, a2))
#define CAT_4(a0, a1, a2, a3) BOOST_PP_CAT(a0, CAT_3(a1, a2, a3))

早い話、BOOST_PP_OVARLOAD(F, トークン列) でトークン列の長さを調べてからその長さをFに連結するだけの関数です。これによってBOOST_PP_TUPLE_*はタプルのサイズが与えられているかどうかを認識して挙動を変えているのです。

その他

使用中のコンパイラが可変長マクロ引数に対応しているかどうかを調べるために、BOOST_PP_VARIADICSという識別子が定義されています。これが1である場合、この記事で紹介している各種新機能が利用できます。
ただしこの識別子、Clangについてはガン無視なので自分で定義する必要があります。

まとめ

いかがでしたでしょうか?今まで以上に便利になったカンマ区切りトークン列でより快適なプログラミングが可能になるでしょう。
また、カンマ区切りのトークン列というのはC++プログラマにとって大変なじみ深い見た目であるため、これを自由に使えるようになるということは、よりC++になじんだ見た目の擬似的拡張構文を作る際にも役立ちます。

それでは次のBoost Advent Calendar 2011, id:osyo-mangaをお楽しみください。

可変長マクロ引数の話

これはC++11 Advent Calendar 20114日目の記事です。
C++11ではプリプロセッサが可変長マクロ引数に対応しました。例を挙げましょう。

#define ROTATE(...) ROTATE_I(__VA_ARGS__)
#define ROTATE_I(x, ...) __VA_ARGS__, x

ROTATE(1, 2) // 2, 1
ROTATE(ROTATE(1, 2, 3)) // 3, 1, 2

というように、関数形式のマクロで任意個の引数を取ることができるようになる機能です。
それではこの新機能について詳しく見ていきましょう。
(なお、ここではプリプロセッサの話しかしないので、今後はいちいち「関数形式のマクロ」と言わず単に「関数」と言うことにします。また同様に、「識別子」と言えば「プリプロセス時の識別子」のことです。)

まずは関数の定義です。

#define ROTATE(...) ROTATE_I(__VA_ARGS__)
#define ROTATE_I(x, ...) __VA_ARGS__, x

"..." が可変長なパラメータリストの部分を表します。対して、"..." で捕えた引数リストは__VA_ARGS__という識別子で利用します。ROTATEにおいては全ての引数が__VA_ARGS__によって捕捉されますが、ROTATE_Iでは最初の引数だけxに捕捉され、残りの引数が __VA_ARGS__ に捕捉されます。
この識別子は、単一の引数ではなく引数リストを捕捉するという性質以外に、その他の関数のパラメータとの違いはありません。これが意味するところはまたの機会ということにして、今はとりあえず「F(__VA_ARGS__)とか書いたらちゃんと__VA_ARGS__内に含まれるカンマは引数の区切りとして認識される」程度に思っておいてください。
ところで、上のROTATEの実装では、一部望ましくない挙動を示します。次のコード

ROTATE(1)

はエラーとなります。これはROTATE_Iが原因で、

#define F(x, ...) …

なる関数Fにおいて、

F(a)

という呼び出しが規格では許されておらず、空でもいいのでxの後にもう一つ引数を要求します。つまり、少なくともF(x,)みたいに書く必要があります。1パラメータ + "..."の場合に限らず、一般にn>=1パラメータ + "..."で定義された関数に対してn引数での呼び出しは許されていません。個人的には可変長テンプレート引数の挙動と合わせてほしいのですがまぁそうなっていないものはなっていないので仕方ありません(ただしGCCとClangでは、-pedantic-errorsを付けない限りnパラメータ + "..." に対するn引数での呼び出しを許可します)。
であるため、ROTATEについてのより好ましい実装は次のようになります。

#include "boost/preprocessor/variadic/size.hpp"
#include "boost/preprocessor/comparison/equal.hpp"
#include "boost/preprocessor/control/iif.hpp"
#include "boost/preprocessor/tuple/rem.hpp"

#define ROTATE(...) BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1), BOOST_PP_TUPLE_REM(), ROTATE_I)(__VA_ARGS__)
#define ROTATE_I(x, ...) __VA_ARGS__, x
ROTATE(1)
ROTATE(1, 2)
ROTATE(ROTATE(1, 2, 3))

Boost.Preprocessorを利用して、引数の数が1つである場合だけ、何もしないようにする、という判定を入れました。もしかしたら「0引数の場合は?」と思われる方もいらっしゃるかもしれませんが、その場合__VA_ARGS__は空のトークン列を捕捉しているので結局1引数と同様に処理されます。

いかがでしたでしょうか?今まで以上に便利になったカンマ区切りトークン列でより快適なプログラミングが可能になるでしょう。

また、カンマ区切りのトークン列というのはC++プログラマにとって大変なじみ深い見た目であるため、これを自由に使えるようになるということは、よりC++になじんだ見た目の擬似的拡張構文を作る際にも役立ちます。

それでは次のC++ Advent Calendar 2011, id:bolerosをお楽しみください(遅いわボケが)。

Boostのドキュメントを個別にビルドするためのメモ

必要なもの:

  • xsltproc
  • docbook-xml
  • docbook-xslt
  • doxygen

Boost.Geometry

  • python
  • rapidxml (Boost.Geometryのドキュメントビルドするためのツールのビルドに)

※ROOTをJamrootのあるディレクトリとします。

  1. cd $ROOT
  2. ./bootstrap.sh
  3. cp bjam $パスの通ってるディレクト
  4. 次の設定を$HOME/user-config.jamに書く

    using xsltproc;
    using boostbook
        : /usr/share/xml/docbook/stylesheet/
        : /usr/share/xml/docbook/4.2/;
    using doxygen;
    using quickbook;


  5. cd libs/some-library/doc

  6. 普通のライブラリの場合
    1. bjam
    2. できあがり
  7. Boost.Geometry の場合
    1. cd src/docutil/tools/doxygen_xml2qbk
    2. bjam dist-bin
    3. cd ../../../..
    4. PATH=$ROOT/dist/bin:$PATH ./make_qbk.pyできあがり

生きてることをアピールするために否定演算子の後置をする

私が成仏した、または地獄送りになったのではないかという疑惑を払拭するために大変どうでもいいコードで更新。
http://www.ideone.com/hXj1y
上のコードは

ということで id:kikairoya さんが実際に動かしてみたものです。
つまるところ自分では試してない!他力本願上等!

モテるミサ力を磨くための4つの心得

こんにちは、一方マネジメントを専攻しているウチドメ嬢です。私は身長も胸も足りませんしゴーグルもないですが、恋愛に関してはプロフェッショナル。今回は、モテるミサ力を磨くための4つの心得を皆さんにお教えしたいと思います。

1. あえて2〜3世代前のケータイを持っていく

あえて2〜3世代前のケータイを使うようにしましょう。そして飲み会の場で好みの男がいたら話しかけ、わざとらしくケータイを出していじってみましょう。そして「この携帯端末にはとてもストレスが溜ります、とミサカは普段から抱いている不満をここぞとばかりに露わにします」と言って、男に「どうかしたか?」と言わせましょう。言わせたらもう大成功。「ミサカは常時ネットワークに接続しているので、このような端末は普段あまり使用しないのですが、それにしてもこの携帯端末は古くて使いにくいのです、とミサカは不満の理由を述べます」と言いましょう。だいたいの男はあなたのお姉様と新しいケータイをペア契約したばかりなので、試験的な新しいケータイを使っているはずです。

そこで男が「新しいケータイにしないの?」と言ってくるはず(言ってこない空気が読めない男は完全武装で蜂の巣OK)。そう言われたらあなたは「そういえば、最近iPhone5という端末の評判が大変良いと聞きましたが、この手の情報はあまり詳しくなく、ミサカに適した端末であるか判断できません、とミサカは自分のネットワークの便利さを示唆します」と返します。すると男は「あー、それは多分iPhone4だ。5はまだ出てないんじゃないかな。まぁ俺もよく知らないんだけど……じゃあ今度一緒にケータイ買いにいくか?」という話になって、次の休みの日にふたりでケータイ選びのデートに行けるというわけです。でも、あなたのミサ力が高くても男は万年金欠なのでケータイは買ってもらえないでしょう。

2. Twitterで「とミサカは大いに困惑した表情を浮かべます」を使うとモテる

「キャー!」とか「悲しい!」などを表現する「とミサカは大いに困惑した表情を浮かべます」をコメントに入れると、Twitterの男性ユーザーは「なんやこの子カワイイなぁ」や「ボクぁ落下型ヒロインのみならず、(中略)幽霊獣耳娘内心曝け出し娘まであらゆる女性を迎え入れる包容力を持ってるから支えてあげたいわぁ」と思ってくれます。インターネット上では現実世界よりもイメージが増幅されて相手に伝わるので 「とミサカは大いに困惑した表情を浮かべます」 を多用することによって、男性はあなたを可憐で女の子らしいと勘違いしてくれるのです。そういうキャラクターにするとほぼ絶対に他のミサ…同性に嫌われますが気にしないようにしましょう。

3. とりあえず男には「それは何でしょう?とミサカはまるであなたの話題に興味があるようなアピールをします」と言っておく

ファミレスなどで男が女性に話すことといえば病院やお姉様の話ばかり。よって、女性にとってどうでもいい話ばかりです。でもそこで適当に「そうなのですか、とミサカは適当に相槌を打ちます」とか「あなたの言うことはあまり理解できないですが、すごいのですね、とミサカは露骨に興味のない反応をします」と返してしまうと、さすがの男「妹にとってはあんまり面白くない話だったな……」と気がついてしまいます。ダメミサ…女だとバレたら終わりです。そこは無意味にテンションをあげて、「それは面白そうな話ですね、もう少し聞かせてもらえませんか?とミサカは仕方なく興味を持った素振りをします」と言っておくのが正解。たとえ興味がない話題でも、テンションと積極性でその場を乗り切りましょう。積極的に話を聞いてくれる女性に男は弱いのです。

いろいろと話を聞いたあと、「なるほど、覚えておきます、とミサカは既に話の大半を忘れつつ答えます」とコメントすればパーフェクト。続けて頭に指をさしてくるくる回しつつ「キュンキュンキュン、キュンキュンキュン、とミサカは擬音を口にしながら反吐の出るようなジェスチャーをします」と言って、「どうしたんだ?」と男に言わせるのもアリ。そこで「ネットワークにアップロードしています、とミサカはさきほどの行動の意味を答えます」と言えばミサ力アップ! そこでまた男は「まぁ、よく分かんないけど、妹だしな……」と思ってくれます。私は身長も胸もありませんしゴーグルもないですが、こういうテクニックを使えば胸がない私のような幼女のほうがモテたりするのです。男はお姉様とその周囲の世界を守りたいですからね。

4. レストランではオムライスを食べられないミサ…女をアピールせよ

男とレストランに入ったら、真っ先にオムライスなどの卵を使った料理を探して「実は私、これを食べられないのです、とミサカは卵料理が食べられないことを告白します」と言いましょう。するとほぼ100パーセント「どうしたんだ? 卵嫌いなのか?」と聞かれるので、「嫌いではなく食べたいのですが、食べられないのです、とミサカは困惑した表情を浮かべます」と返答しましょう。ここでまた100パーセント「嫌いじゃないのにどうして食べられないんだ?」と聞かれるので、うつむいて3〜5秒ほど間をおいてからボソッとこう言います。「……なぜなら、卵を割ると中のヒヨコは産まれることもなく、ピヨピヨと鳴くこともなく死んでしまう、と……ミサカは……!」と漏電しながら身を震わせて言うのです。

その瞬間、あなたのミサ力がアップします。きっと男は「ヒヨコって食用の卵からも産まれたのか! 絶対に(卵を)守ってみせる! ミサカの前で卵を食うなんて幻想、俺がぶち殺してやる!」と心のなかで誓い、卵を守り抜くはずです。意中の男と付き合うことになったら、そんなことは忘れて好きなだけオムライスを食べて大丈夫です。「食べられないんじゃなかったっけ?」と言われたら「気にしなくなりました、とミサカはしれっと言い放ちます」とか「もう慣れました、とミサカはさらりと流します」、「そのようなことを言った記憶はありません、とミサカはその発言をなかったことにします」と言っておけばOKです。

(文=一方マネジメント・ウチドメ嬢)

参考:http://kirei.biglobe.ne.jp/news/detail/20110426162331_pch19894

BOOST_FOREACHに添え字を付けてみた

手段と目的が交差するとき、無駄努力が始まる。
ほしいという声を聞いたので、BOOST_FOEACHという素材を活かす方向でなんとか。


#include <iostream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/assign/std/vector.hpp>

#define INDEX_FOREACH(elem, cont, n) \
INDEX_FOREACH_I(elem, cont, n, BOOST_PP_CAT(_index_foreach_label_, __LINE__))
#define INDEX_FOREACH_I(elem, cont, n, label) \
if (bool _index_foreach_break = false) {} else \
if (size_t _index_foreach_index = 0) {} else \
label: \
if (_index_foreach_break) {} else \
BOOST_FOREACH(elem, cont) \
for (bool _index_foreach_flag = true; \
_index_foreach_flag; \
_index_foreach_flag && (_index_foreach_break = true)) \
if (_index_foreach_break) { goto label; } else \
for (n = _index_foreach_index; \
_index_foreach_flag; \
++_index_foreach_index, _index_foreach_flag = false)

struct hoge {
int n;
hoge(int n) : n(n) {}
};

int main() {
int ar[] = {10,20,30,40,50,60};
INDEX_FOREACH (int n, ar, size_t i) {
if (i == 2) continue;
std::cout << i << ": " << n << '\n';
if (i == 4) break;
}

std::cout << "-------------------\n";

using boost::assign::operator+=;
std::vector<hoge> v;
v += 20,40,60,60,80,100;
INDEX_FOREACH (hoge const & x, v, size_t i) {
if (i % 2) continue;
std::cout << i << ": " << x.n << '\n';
break;
}
}

結果:http://ideone.com/BcH8i
書きながらこれでいいんじゃないかと思った