Namaran

Code daily. Without assist.

2026-08-23

describe_length.cpp

#include <print>
#include <variant>
#include <string>

struct Meters { double value; };
struct Feet { double value; };

template <class... Fs>
struct overloaded : Fs... { using Fs::operator()...; };
template <class... Fs>
overloaded(Fs...) -> overloaded<Fs...>;

using Length = std::variant<Meters, Feet>;

std::string describe(const Length& len) {
    // write this: using std::visit and the overloaded helper above (not a
    // switch on len.index()), return "{value}m" for Meters and "{value}ft"
    // for Feet, built with std::format
}

describeを実装してください。len.index()switchで分岐させるのではなく、std::visitoverloadedを使うこと。

Reference
std::string describe(const Length& len) {
    return std::visit(overloaded{
        [](const Meters& m) { return std::format("{}m", m.value); },
        [](const Feet& f) { return std::format("{}ft", f.value); },
    }, len);
}

std::visitに渡したoverloaded{...}Meters用とFeet用のoperator()を1つずつ持つオブジェクトで、lenが実際に保持している型に応じてどちらかが呼ばれます。これはC++にパターンマッチング構文が無い代わりの書き方で、switchと違い、Lengthに新しい型を1つ足すとoverloadedの方も対応するラムダを足すまでコンパイルが通らなくなるという利点があります(switch (len.index())だと、新しいケースを足し忘れてもコンパイラは何も言ってくれません)。これは参考実装であり、唯一の正解ではありません。