Date: Mon, 26 May 2025 11:14:14 -0400
The main thing lacking from this entire thread has been any semblance of a
discussion of codegen.
The reason C supported `switch` from the beginning is that integers can be
put into jump tables:
switch (i) {
case 1: case 4: ~~
case 2: ~~
case 5: ~~
}
turns into the codegen equivalent of (Godbolt
<https://godbolt.org/z/Tqn31Eqhs>)
if (1 <= i && i <= 5) {
Address table[] = {&&a1, &&a2, &&pass, &&a1, &&a5};
goto *table[i];
a1: ~~
a2: ~~
a5: ~~
pass: ;
}
It would be very cool if C++ could do that for arbitrary user-defined types
such as `std::string`... but let's start super simple, with a type where we
needn't even think about hashing yet — just a simple wrapped integer.
class WrappedInt {
int i_;
public:
constexpr WrappedInt(int i) : i_(i) {}
std::strong_ordering operator<=>(const WrappedInt& rhs) const;
bool operator==(const WrappedInt& rhs) const;
};
int main(int argc, char **argv) {
auto w = WrappedInt(argc);
switch (w) {
case WrappedInt(1): case WrappedInt(4): ~~
case WrappedInt(2): ~~
case WrappedInt(5): ~~
}
}
Notice that WrappedInt doesn't have a conversion to `int`. (If it did, we
could just switch on *that*, which would make this whole feature
unnecessary.) All it has, so far, is comparison operators, which are
obviously not good enough to build a jump table in the codegen.
So (this is a probably-rhetorical question directed at @ZhaoYunshan) what
API would you have to require of the author of WrappedInt in order to make
their type "switch-able"?
Remember, the `switch` statement is *not just syntactic sugar* for an
if-else-if chain of `operator==` comparisons. That chain is slow, and we
can already write it by hand if that's what we mean. If you want `switch`
for user-defined types, you'll have to explain *how to codegen it*.
Without any idea how to codegen it, you're not doing language design —
you're just stringing words together in teletype font.
HTH,
Arthur
On Tue, May 20, 2025 at 7:38 AM Zhao YunShan via Std-Proposals <
std-proposals_at_[hidden]> wrote:
>
> In C++, the switch statement is a fundamental control-flow construct
> originally designed to work only with integer types (int, char, enum,
> etc.). However, in real-world development, programmers often need to handle
> string-based (std::string) branching logic. While the standard syntax
> does not natively support strings, well-structured design patterns can
> still leverage switch-like behavior to replace lengthy if...else if chains,
> significantly improving code readability and conciseness.
>
> #include <iostream>
> #include <string>
> int main()
> {
> std::string router;
> switch (router)
> {
> case "cpp":
> std::cout << "cpp router selected.";
> break;
> case "hpp":
> std::cout << "hpp router selected.";
> break;
> default:
> std::cout << "Unknown router type.";
> break;
> }
> return 0;
> }
>
>
> By leveraging compile-time static analysis, switch statements can be
> optimized into various efficient data structures:
>
> * Jump tables* for few cases,
> * Balanced binary search* for many branches,
> * Hash tables* where supported.
>
> This ensures optimal time complexity (*O(1)* to *O(log n)*) even with
> large branch sets.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
discussion of codegen.
The reason C supported `switch` from the beginning is that integers can be
put into jump tables:
switch (i) {
case 1: case 4: ~~
case 2: ~~
case 5: ~~
}
turns into the codegen equivalent of (Godbolt
<https://godbolt.org/z/Tqn31Eqhs>)
if (1 <= i && i <= 5) {
Address table[] = {&&a1, &&a2, &&pass, &&a1, &&a5};
goto *table[i];
a1: ~~
a2: ~~
a5: ~~
pass: ;
}
It would be very cool if C++ could do that for arbitrary user-defined types
such as `std::string`... but let's start super simple, with a type where we
needn't even think about hashing yet — just a simple wrapped integer.
class WrappedInt {
int i_;
public:
constexpr WrappedInt(int i) : i_(i) {}
std::strong_ordering operator<=>(const WrappedInt& rhs) const;
bool operator==(const WrappedInt& rhs) const;
};
int main(int argc, char **argv) {
auto w = WrappedInt(argc);
switch (w) {
case WrappedInt(1): case WrappedInt(4): ~~
case WrappedInt(2): ~~
case WrappedInt(5): ~~
}
}
Notice that WrappedInt doesn't have a conversion to `int`. (If it did, we
could just switch on *that*, which would make this whole feature
unnecessary.) All it has, so far, is comparison operators, which are
obviously not good enough to build a jump table in the codegen.
So (this is a probably-rhetorical question directed at @ZhaoYunshan) what
API would you have to require of the author of WrappedInt in order to make
their type "switch-able"?
Remember, the `switch` statement is *not just syntactic sugar* for an
if-else-if chain of `operator==` comparisons. That chain is slow, and we
can already write it by hand if that's what we mean. If you want `switch`
for user-defined types, you'll have to explain *how to codegen it*.
Without any idea how to codegen it, you're not doing language design —
you're just stringing words together in teletype font.
HTH,
Arthur
On Tue, May 20, 2025 at 7:38 AM Zhao YunShan via Std-Proposals <
std-proposals_at_[hidden]> wrote:
>
> In C++, the switch statement is a fundamental control-flow construct
> originally designed to work only with integer types (int, char, enum,
> etc.). However, in real-world development, programmers often need to handle
> string-based (std::string) branching logic. While the standard syntax
> does not natively support strings, well-structured design patterns can
> still leverage switch-like behavior to replace lengthy if...else if chains,
> significantly improving code readability and conciseness.
>
> #include <iostream>
> #include <string>
> int main()
> {
> std::string router;
> switch (router)
> {
> case "cpp":
> std::cout << "cpp router selected.";
> break;
> case "hpp":
> std::cout << "hpp router selected.";
> break;
> default:
> std::cout << "Unknown router type.";
> break;
> }
> return 0;
> }
>
>
> By leveraging compile-time static analysis, switch statements can be
> optimized into various efficient data structures:
>
> * Jump tables* for few cases,
> * Balanced binary search* for many branches,
> * Hash tables* where supported.
>
> This ensures optimal time complexity (*O(1)* to *O(log n)*) even with
> large branch sets.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2025-05-26 15:14:32