これはC++ Advent Calendar 201911日目の記事です
昨日は@segurさんのC++版FBX SDK入りのDockerイメージを作ってみるでした
このエラー結構遭遇しますよね?
std::min
とかstd::max
std::clamp
のように関数の引数が
template <class T>
T hoge(T x1, T x2, ...);
template <class T>
T huga(std::initializer_list<T> t);
みたいになっている場合の関数でこんな呼び出しをしたいことが結構ある
double x = ...;
x = std::clamp(x, 0, 1); // xを[0,1]に収めたい
しかしこれだとTが推論できなくてコンパイルエラーになる
prog.cc:6:9: error: no matching function for call to 'clamp'
x = std::clamp(x, 0, 1);
^~~~~~~~~~
/opt/wandbox/clang-head/include/c++/v1/algorithm:2649:1: note: candidate template ignored: deduced conflicting types for parameter '_Tp' ('double' vs. 'int')
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi)
^
/opt/wandbox/clang-head/include/c++/v1/algorithm:2638:1: note: candidate function template not viable: requires 4 arguments, but 3 were provided
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi, _Compare __comp)
^
オーバーロードが多いstd::min
とかだと結構な数のエラーが出る
https://wandbox.org/permlink/xXkJXYMNqMW7PI3d
そして仕方なくこんな感じの対処をすることが多い
std::clamp(x, 0., 1.); // 小数点をつけて浮動小数点リテラルに変更した
でもさ
リテラルだったらいいけど何か変数だったときがめんどくさい
int l = ..., h = ...;
std::clamp(x, static_cast<double>(l), static_cast<double>(h));
int y = ...;
float z = ...;
std::min({x, static_cast<double>(y), static_cast<double>(z)});
え?C言語スタイルのキャストなら短く書ける?またまたご冗談を
推論できないなら
推論させなければいいじゃない
std::clamp<double>(x, l, h);
簡潔だし戻り値の型がハッキリしてるのもよい
initializer_list
の方も問題なく使える
std::min<double>({x, y, z});
ただし縮小変換に伴う警告はしっかり出るのでそこら辺で結局キャストをそこそこ使うような気もする(でもこの場合だと出ない。c++って難しい)
参考までに
std::gcd
std::lcm
はテンプレート引数が2つに分かれているので今回の例には当てはまらない(符号の有る無しで結果を分けてるみたい)
明日は
@kizulさんのC/C++間での翻訳フェーズの違い です