よくわからないけど、やりたいことがC++20じゃなくてもできた話

いきなり本題

よくわかりませんが、自分の実装したかったことがC++20じゃないとできないと思っていたら、なぜかGNU++17で通ってしまいました。仕様を誤解してるんですかね??

やりたかったこと

普段使っている prt(T t,string end="\n")関数、これがちょっと不便。

template<typename T>
void inline prt(T t,string end="\n"){cout<<t<<end;}
int main(){
  int x;
  cin>>x;
  prt("x",":");prt(x);
}

これをもうちょいなんとかきれいにしたかった。

int main(){
  int x;
  cin>>x;
  prt("x",":")(x);
}

こんな風にできたらわかりやすくていいんじゃね???てことで実装

実装

失敗

template <typename T>
auto prt(T t, string end = "\n") {
  cout << t << end;
  return prt;
}

ずっとこれでいけると思ってました…
だめなんですね…

実装例①

直接関数を返すことができなかったのでラムダ式を挟むようにしました。

auto prt(auto t, string end="\n") {
  cout << t << end;
  return [](auto t, string end="\n") { return prt(t, end); };
}
// または
template<typename T>
auto prt(T t,string end="\n"){
  cout << t <<endl;
  return [](auto t, string end="\n") { return prt(t, end); };
}

このプログラムは期待通りに動きます!

①の問題点

競プロで使う際の、実用上の問題は特にないかと思います。
実際、autoを引数にとるラムダ式はtemplateに展開されます。
(参考ページ)
しかし!!!引数がautoだったり、autoとtypenameが混ざっていたりするので(あくまで見た目的に)何とも言えない微妙な関数になっています!

なっているのです!

改善方法

つまり、ラムダ式でtemplate<typename T>が使えれば解決するんです
調べました。
あります!!!!

しかし、これC++20から使える機能のようで、AtCoderでは現在GNU++17なので使えない…

… …
使える!?
なんで!????

ということでよくわからないけどうまくいったものがこちらになります。

template <typename T>
auto prt(T t, string end = "\n") {
  cout << t << end;
  return []<typename U>(U u, string end = "\n") { return prt(u, end); };
}

なんとなく統一感のあるいい感じのプログラムですよね!

いい感じですね!すっきりしてます。

もちろん小数なども問題なく出力できます!

まとめ

ほんとになんでできたんですかね…
有識者の方、アドバイスをいただけると嬉しいです!!

あと、一応ですがこの記事は1/4くらいはおふざけです。
どちらにせよ、前述のとおり auto を使って問題ありません
(内部的にはtemplateが使われた関数になるので)

理解の間違いの指摘、お待ちしております。

この記事が気に入ったらサポートをしてみませんか?