C++erを簡易的にレベル分けすることで初心者詐欺を減らそうという試み

  • 189
    Like
  • 0
    Comment

はじめに

こんなTwitterでのやり取りから生まれた。C++erで「初心者です」って言う人多いけど全然初心者じゃない人かなりいるよね、ということで作った。

レベル関係

C初心者 < C++初学者 < C++入門者 < C++初心者 < C++規格書リーディング初心者 < C++中級者 < C++規格書リーディング中級者 < C++上級者 < C++規格書クラッカー

それぞれ見ていく

あくまで上限ラインを書いているだけだからstdioがなんの略か知らなくてもC初心者よりしたというわけではない。

C初心者

「なんか変数とかいうのがあって型とかいうのがあるらしいな。puts関数やprintf関数で標準出力に出力、fgetsで標準入力から入力を受けられるらしい」 という程度の状態、およびそれ以下である。stdioがStandard Input/Outputの略だと知っていることもある。ポインターとか配列は「なにそれ美味しいの」という状態

#include <stdio.h>
int main(void)
{
    puts("arikitari na world!");
    return 0;
}

C++初学者

C++初学者とは、iostreamヘッダーに標準入出力のクラス、関数群があることを知っていて、関数のオーバーロードを使ったことがある程度の状態である。

#include <iostream>
void foo(int n){
    std::cout << "void foo(int) called( n = " << n << ")." << std::endl;
}
void foo(double n){
    std::cout << "void foo(double) called( n = " << n << ")." << std::endl;
}
int main()
{
    std::cout << "arikitari na world!" << std::endl;
    foo(3);
    foo(3.14);
}

C++入門者

C++入門者とはclassの存在を知っていて書いたことがあり、またstd::stringstd::vectorstd::arrayを操れ、algorithmヘッダーを使ったことがあり、range-based forを使える程度の状態である。なんとなくtemplateを使ってみたことがある状態を含む

#include <iostream>
#include <array>
#include <vector>
#include <numeric>
void print(const std::vector<int>& vec)
{
    for(auto&& v : vec) std::cout << v << ',';
    std::cout << std::endl;
}
template<std::size_t N> void print(const std::array<int, N>& arr)
{
    for(auto&& a : arr) std::cout << a << ',';
    std::cout << std::endl;
}
int main()
{
    std::vector<int> v;
    v.resize(4);
    std::iota(v.begin(), v.end(), 0);
    std::array<int, 3> arr{{ 3, 1, 4 }};
    print(v);
    print(arr);
}

C++初心者

C++初心者とは作りたいものを不格好でも作れ(なんでもいいんです、少しでも自分で動かしてみたいと思うものが作れれば)、またcpprefjpなどを使い分からないことを調べることができ、コンパイル時定数の存在を知っていて、rvalue reference、template特殊化、簡単なSFINAEを使ったConceptのようなコードが理解でき書ける程度の状態である

分類したけどC++初心者の幅はやっぱり大きい。

なおNew Game!のねねっちはここ。NeneEngineというエンジンを自作しているたぁ驚きだね。

ねねっちのコード
void DestructibleActor::Init()
{
    NeneActor::Init();
    m_currentHealth = m_maxHealth;
}

// 攻撃を食らった時のダメージ計算
void DestructibleActor::RecieveDamage(float sourceDamage)
{
    //デバフを適用
    auto resolvedDamage = sourceDamage;
    for(const auto& debuf : m_debufs)
    {
        resolvedDamage = debuf->ApplyToDamage(resolvedDamage);
    }
    m_currentHealth -= resolvedDamage;
    if(m_currentHealth <= 0.f)
    {
        m_currentHealth = 0.f;
        DestroyMe();
    }
}

//破壊せよ!
void DestructibleActor::DestroyMe()
{
    //死亡モーションがあれば再生
    //TOTO: 死亡モーションを作る!
    if(m_pDeathMotion)

    //筆者注:この下は画像が見切れていて読めない
}

debufの型はstd::shard_ptr<C>かな?

C++規格書リーディング初心者

C++規格書リーディング初心者とは、分からないことは規格書も参照しようと思えば本の虫などを見つつなんとかでき、またオーバーロード(ADL含む)や型推論の詳細な仕組みをそこそこ理解できている程度の状態である

C++中級者

C++中級者とは Boost Range LibraryのOven拡張のようなoperator overloadテクニック(operator|を使ったメソッドチェインもどき)を自作でき、boost.asioを使え、C++11constexprの大変さを語れる状態である。また、継承を使いこなせており、なぜC++において継承だらけのプログラムをあまり見なくなったのかを自らの原体験を元に語れる状態である。

C++規格書リーディング中級者

C++規格書リーディング中級者とは 最新規格書をすべて一度は通読し、他人のコードの誤りを規格書を参照して論理的に指摘でき、コンパイラのバグを発見できる状態である。

C++上級者

C++上級者とはCとC++の規格書、公開されている標準化委員会の文書ほぼすべてに目を通していること、最新規格に対応しつつコンパイラのバグを回避しつつ何かしらのライブラリを作れる状態である。

C++規格書クラッカー

C++規格書クラッカーとは、C++標準化委員会に提案が出来る程度の知識と経験を持ち、また規格書のバクを発見できる程度の状態である。つまり江添さん。岡山の陶芸家な中3女子もきっとここ

反響

Twitterより

はてなブックマークより

http://b.hatena.ne.jp/entry/qiita.com/yumetodo/items/a843bd542106215bbc84

抜き出すとまさかりが飛んできそうなので各自見てください。

まとめ

異論はたくさんあると思うけど、C++初心者怖い状態がなくなればいいなと思います。

え?私?多分C++規格書リーディング初心者だと思う。

追記

どうもC++規格書リーディング初心者は長過ぎるようで「初心者ってことでいいよね?」という声が聴こえる。・・・いやダメだろ。

なんでboost.asioだけ出てきているかというと、あれを使えるということはcallback地獄への対処のためにいろいろ知っていないといけないので、という意味で上げました。断じてC++初心者(boost.asioが使えないとは言っていない)の人を弾くためではない

対抗記事とか他言語版記事とか出ないかな(チラッ

このレベル分けで「20年プログラマ」やってるけど(ryが発生しているのは、あくまでC++の言語仕様に着目してレベル分けしているからで、「計算機科学」「ツール・文化」「ドメイン知識」とかとかの分野別に分けていないから。だから簡易的という言葉で逃げてたんですね。

あ、MFCとかC++/CLIはお帰りください。

なんか誤解を与えているようなので追記しますが、C初心者<C++初学者となっているのは、C++の下位言語としてCがあると言っているわけではなく、C++をやるのにCの知識は多少必要だと言いたいだけです。Cを使いこなせることとC++を使いこなせることは全く別方向の話ですので誤解のないように。

なるほど・・・?

冒頭で触れた、C++初心者(boost.asioが使えないとは言っていない)の人が
C++ステップアップにむけて 段階を作ってみた - Qiita
なんていう記事を書いたようだ。。なるほど、面白い。

この記事を書いた意図について

ようやくこの記事のviewの伸びも収まってきたのと、某所で誤解を受けていたのでこっちにも意図を書いておきますか。

この記事は、現代のC++があまりにも難解になっているのでおおよそ仕様をすべて把握し、C++の言語としての特性を、コーディングを実際にするユーザーがうまく利用して「楽をする」ことができなくなっているな、と思ったので、記事冒頭のツイートをきっかけに書いたものです。

http://b.hatena.ne.jp/entry/287284443/comment/q7z
q7zのコメント 2016/05/13 23:11
こういう言動がホントに初心者に迷惑かけてることに気づいてないんだろうな。敬遠されるような事をして悦に入ってるだけ。

というコメントがはてなブックマークについていますが、ある意味狙い通りです。
よっぽど記事中に引用しようかと思いましたが、無駄にview数が伸びてたので炎上しそうで、「抜き出すとまさかりが飛んできそうなので各自見てください。」と書くにとどめましたが、
このコメントを見てくれた人はどのくらいいたんだろうか。

だって、現代見かけるC++のコードを書くために覚えることがあまりにも多すぎるじゃないですか。
実際のところ私は継承もオーバーロードも理解しきれていませんし。

で、本来、プログラミング言語そのものを相当知らないと水準のコードが書けないというのはおかしいはずです。たかが道具なのに。
ところがC++の場合、言語仕様を半ば悪用したトリッキーなコードがデファクトスタンダードになっているがために、言語そのものを相当勉強しないといけない。
せめてRustみたいにコンパイルエラーがわかりやすければまだ良かったかもしれないがそれすらないからユーザーはライブラリの実装を読んで理解しないといけない(Conceptはよ)。

少なくとも私は、みなさんと違ってC++11から入門した人間ですが、当時江添さんの本の虫の記事を必死に読み漁り(もちろんググりながらなのでfaithandbraveさんはじめ多くの人の記事もよみました)、
やっとこのわけわかんないコートはどうしてこれ以上わかりやすくかけないのか、おぼろげに理解できるようになるまで約半年、本当に大変でした。なんせC++にはまともな入門本すらないですからね。

現状のC++の存続意義は過去の資産の活用と速度追求の2点に絞られると思っています。速度を追求しないのであればほかにいくらでも適当な、かんたんな言語はあるはずです(C#とかRustとかGo?)。
逆に言えば速度追求のためならなんでも許される、そういう空気を私は感じています。これがますますC++を難解にさせている原因かもしれません。

[C++11]lambda、[C++11]ravlue reference、[C++14]constexpr、[C++17]template classの実引数推定や[はよこい]Conceptなど改善がないわけではないですが、
少なくとも私は今後輩にC++を勉強してみたら?とは言えません。実際JavaScriptとRustを勧めてます。
今のC++界隈の状況で、C++入門したら、無駄に時間が消し飛んで振り回されるだけです。まじで今のC++おかしいんじゃねーの?私はC++が好きだから使い続けるけど。

まあしかし、この記事View数伸びすぎてませんかね?
なんでああいうランク分けがC++においてのみ成立して、またこれだけview数があって(さっき確認したら23739views!?)

対抗記事とか他言語版記事とか出ないかな(チラッ

と煽ってなお他の言語版の記事が出ない理由は何なのかまでちゃんと伝わっているとは思えないし。

まあせめてあの記事を見てC++から離れた初心者がいれば、すこしは意味があったのかな、上述の内容が伝わらなくても。この記事書いたときはそこまで思ってなかったけど。

せめてC++17に対応したまともな入門書が出てくれないですかね?一時期本気で書こうかと思ったけど、私の大学の単位が消し飛ぶので自重しています。
江添さんが
https://github.com/EzoeRyou/cpp17book
を書き始めているけど、これは入門書ではないし。