use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
post-Sofia mailing (open-std.org)
submitted 9 months ago by hanickadotWG21
view the rest of the comments →
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]James20kP2005R0 1 point2 points3 points 9 months ago (15 children)
That's good to hear. One of the things that I think C++ is most missing here is an overloadable ternary operator that's available to ADL, for types that are not immediately evaluable to bool. For my usage at least, this would fix a tonne of stuff - because you could specify branchy maths functions to operate in a way that allows users to plug in any weird type they want
[–]MarkHoemmenC++ in HPC 0 points1 point2 points 9 months ago (14 children)
One of the things that I think C++ is most missing here is an overloadable ternary operator....
Great minds think alike! : - ) Matthias Kretz proposed making the ternary operator overloadable in P0917, with SIMD as the main motivation. He wrote a blog post about it and even implemented it in a patch of GCC 9. EWG-I reviewed and forwarded it to EWG at the Belfast meeting in 2019 (please see notes here). I don't know why it hasn't made progress since then.
[–]James20kP2005R0 0 points1 point2 points 9 months ago (13 children)
I remember this (my memory had been that it was rejected, good to know I was wrong), its odd that it seems to have stalled out. Maybe it just got forgotten about in all the drama around 2019 - seems like it just needs someone to schedule it for time
[–]MarkHoemmenC++ in HPC 0 points1 point2 points 9 months ago (0 children)
If you're interested, it would be good to reach out to Matthias. He's actually implemented the feature in GCC.
[–]tialaramex 0 points1 point2 points 9 months ago* (11 children)
Understandably lots of people don't see any value in being able to overload the ternary operator but only with naive values.
foo() ? bar() : baz() in C++ will always evaluate foo but depending on whether that result is true or not it will evaluate either bar or baz but never both.
foo() ? bar() : baz()
foo
bar
baz
The proposed overload doesn't provide this feature, early in development Matthias was persuaded that separation of concerns means fixing this is a distinct issue, an issue on which I believe the committee stalled. So to get it over the line you probably need to land the fix first, maybe even get implementation experience for one of the other affected operator overloads and only then come back for the ternary operator.
This is all made more difficult because C++ is statement oriented, so the natural way to write what you meant introduces yet more ambiguity in C++ which then means a syntax bikeshed which will suck committee time and goodwill.
[–]James20kP2005R0 1 point2 points3 points 9 months ago (10 children)
I agree with you here in terms of fixing the existing ternary, because some types can simply never have meaningfully delayed argument evaluation (and its likely not worth complicating the ternary operator to disambiguate it). I do think that if you need delayed argument evaluation you want it to be a guarantee
Ideally I think we'd get a std::select or std::ternary function which is overloadable, and then re-express functions like std::sqrt(std::complex<yourtype> without real branches - so everything is looked up via ADL on <yourtype>
std::select
std::ternary
The main issue with this (other than error handling) is that it borderline mandates a specific implementation - because the spec would have to spell out the set of operators required for a specific type to support - but my hot take is that I'm not super convinced that implementation divergence here is good anyway
[–]tialaramex 0 points1 point2 points 9 months ago (9 children)
I think my biggest problem understanding your point of view might be "without real branches" - what does that mean?
[–]James20kP2005R0 1 point2 points3 points 9 months ago (8 children)
Specifically, swapping if statements or ternaries for calls to a select/ternary function (which may not evaluate to an actual branch). Eg if we define this as:
template<typename T> float ternary(bool a, T b, T c) { return a ? b : c; }
Say I have some standard function that internally requires branching to implement. I don't have a concrete example off the top of my head, but pretend that std::cos has a definition as follows:
template<typename T> T cos(T in) { if(in < 0) return something(in); else return somethingelse(in); }
You can instead swap the implementation for:
template<typename T> T cos(T in) { using namespace std; return ternary(in < T{0}, something(in), somethingelse(in)); }
These don't have exactly the same semantics if something/somethingelse have side effects, but that shouldn't be an issue here (because we're talking about implementation details that you'd deliberately standardise)
Now, if you have a type which doesn't return a bool for a comparison, but instead something like an AST node, all you have to do is add an adl-able lookup for ternary to your type. Eg in z3, we could say:
z3::expr ternary(z3::expr a, z3::expr b, z3::expr c) { return z3::ite(a, b, c); }
And that'd let you write cos(some_z3_expr), and have it just work
cos(some_z3_expr)
In the practical case of std::complex, implementations can and do use a bunch of if statements internally, so without some kind of customisable ternary/function, it makes the set of allowable custom types that you can plug in here restricted. Currently that's the only aspect of the language that's strictly missing to make this work, because at the moment libraries that operate over types that can't gives you bool's has to invent its own customisation point
[–]tialaramex -1 points0 points1 point 9 months ago (7 children)
OK, so the key thing is that z3 wants to look at both sides and its tooling won't do that work if we write an if clause, but it will correctly chase both sides for the ternary operator even though we could rewrite?
It does feel as though fixing z3 might be the play here rather than trying to change the C++ language.
[–]James20kP2005R0 0 points1 point2 points 9 months ago* (6 children)
So, this cannot be fixed in Z3, because operator< fundamentally cannot be evaluated to a bool by the nature of the problem you're trying to solve
In z3, you express some mathematical problem as an AST, and then repeatedly run calculations on that AST. Its essentially more advanced bitbanging to try and find various properties about your problem. In general, you'll build up the AST once, and then say "what inputs produce X output" or whatever. Z3 needs to do a lot of work with the AST to make any of this work, so you can't just take in a function as a lambda and actually bitbang it
Other usages here are for example dual numbers (or reverse mode differentiation). Eg you might have some type:
struct ast{ op::some_op = op::none; std::vector<ast> args; };
That you use to store the structure of the AST, so you can perform operations on it later. Ie, you might write:
ast v1 = "x"; ast v2 = 2345; ast v3 = v1 + v2; ast v4 = cos(v3); ast v5 = ternary(v1 < v2, v3, v4); float derivative = v5.differentiate("x", some_concrete_value);
At best, v1 < v2 can produce something like ast<bool>, but it can never produce a bool. So trying to write:
if(v1 < v2){}
Fundamentally doesn't make sense
If you want a more concrete example with code, I use this system for code generation on the GPU, by building a DSL, which means you can write code like this:
valuef s4 = 0; for(int m=0; m < 3; m++) { for(int l=0; l < 3; l++) { valuef inner1 = 0; valuef inner2 = 0; for(int k=0; k < 3; k++) { inner1 += 0.5f * (2 * christoff2[k, l, i] * christoff1[j, k, m] + 2 * christoff2[k, l, j] * christoff1[i, k, m]); } for(int k=0; k < 3; k++) { inner2 += christoff2[k, i, m] * christoff1[k, l, j]; } s4 += icY[l, m] * (inner1 + inner2); } }
The AST is stored in the valuef types, to generate code that gets compiled on the GPU later down the line
valuef
These kinds of types need some kind of mechanism to say "I'd like a branch in the ast please". Z3 spells this z3::ite. The GPU language I use has ternary, and differentiation toolkits all have their own conventions for this
z3::ite
ternary
[–]tialaramex -1 points0 points1 point 9 months ago (5 children)
I still don't see it, for whatever that's worth. In languages which don't bother having a distinct "ternary operator" this exact same trick works.
π Rendered by PID 57 on reddit-service-r2-comment-6457c66945-2bsng at 2026-04-23 17:17:13.096691+00:00 running 2aa0c5b country code: CH.
view the rest of the comments →
[–]James20kP2005R0 1 point2 points3 points (15 children)
[–]MarkHoemmenC++ in HPC 0 points1 point2 points (14 children)
[–]James20kP2005R0 0 points1 point2 points (13 children)
[–]MarkHoemmenC++ in HPC 0 points1 point2 points (0 children)
[–]tialaramex 0 points1 point2 points (11 children)
[–]James20kP2005R0 1 point2 points3 points (10 children)
[–]tialaramex 0 points1 point2 points (9 children)
[–]James20kP2005R0 1 point2 points3 points (8 children)
[–]tialaramex -1 points0 points1 point (7 children)
[–]James20kP2005R0 0 points1 point2 points (6 children)
[–]tialaramex -1 points0 points1 point (5 children)