2026-09-18
number_format.cpp
#include <iostream>
#include <string>
#include <variant>
template <class... Fs>
struct overloaded : Fs... { using Fs::operator()...; };
template <class... Fs>
overloaded(Fs...) -> overloaded<Fs...>;
using Number = std::variant<int, double>;
std::string describe(const Number& n) {
return std::visit(overloaded{
[](double d) { return std::to_string(d); },
}, n);
}
int main() {
Number a = 3;
std::cout << describe(a) << '\n';
}
aはintの3を保持していて、"3"が出力されるつもりですが、実際には"3.000000"になります。何が問題で、どう直せばよいでしょうか?
Answer
overloadedにはdouble用のoperator()しかなく、int用を書き忘れています。Numberに新しい型を足したらswitch (n.index())を直し忘れてもコンパイラが黙っている、という前回の問題と違い、std::visitは型を網羅しているかを一応チェックします。しかし、そのチェックは「渡した実引数の型と完全に一致するか」ではなく「暗黙変換も含めて呼び出し可能か」なので、intからdoubleへの暗黙変換がある限り、これはコンパイルが通ってしまいます。aが実際に保持しているintの3は暗黙に3.0へ変換されてdouble版が呼ばれ、std::to_string(3.0)の"3.000000"になります。int用のオーバーロードを足せば直ります:
std::string describe(const Number& n) {
return std::visit(overloaded{
[](int i) { return std::to_string(i); },
[](double d) { return std::to_string(d); },
}, n);
}