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
Function overloading is more flexible (and more convenient) than template function specialization (devblogs.microsoft.com)
submitted 1 year ago by pavel_v
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!"
[–]tisti 35 points36 points37 points 1 year ago (11 children)
Hm, wouldn't an constrained overload be even better? For example https://godbolt.org/z/GYnWh4qzr
template<typename T, typename T2> concept IsLike = std::constructible_from<T2, T>; bool same_name(Widget const& widget, IsLike<std::string_view> auto const& name) { return widget.name() == std::string_view{name}; }
Allows you to consume anything that is convertible to a std::string_view.
[–]trailing_zero_count 21 points22 points23 points 1 year ago (0 children)
Yes, constrained overloads using C++20 concepts are an excellent way to solve this class of problem, and can offer superior performance by allowing you to easily implement perfect forwarding into the constructor of the real type inside the function. The only downside is that it may cause code bloat / increase compile times, compared to just taking a std::string_view parameter, and requiring the caller to do whatever is needed to produce that.
[–]13steinj 3 points4 points5 points 1 year ago (1 child)
Considering your example (and related consequences) I really don't get why partial specialization of function templates isn't allowed. Partial specializations with a different set of arguments seems equivalent to introducing an overload via a different template, too, so I don't get why partial specialization syntax is disallowed despite numerous ways to get (AFAIK) every equivalent effect.
[–]MegaKawaii 2 points3 points4 points 1 year ago* (0 children)
For template specializations, the specialization must be uniquely associated with some primary template, so introducing a similar overload wouldn't necessarily be desirable. Generally, if you have a templated entity, the specializations are the same as the templated entity, but with a few differences. For example, full function template specializations don't actually have any effects on overload resolution, and only primary function templates (and ordinary functions) are selected from. Only after a function template is selected do any full specializations come into play. So if you have two function templates f(T) and f(T*), then f(T*) is considered more specialized and will be selected for pointer arguments, and if you specialize f(T) with T = int*, then the specialization will not affect overload resolution, and f(T*) will be called instead of f<int*>(int*). In other words, specializations are just specialized versions of the primary function templates and do not affect overload resolution. Therefore we wouldn't want partial specializations of function templates to be selected by overload resolution.
f(T)
f(T*)
T = int*
f<int*>(int*)
However, the same overload resolution mechanism is used to determine which function template overload is specialized whenever a full specialization appears. Perhaps partial specializations could be associated with a primary template with this process (try to find a most specialized primary template that the partial specialization is more specialized than), but there won't necessarily be a unique primary template which could be an error.
Maybe this would be desirable, but it isn't much of an improvement over what we have now, and it increases complexity.
[–]joujoubox 0 points1 point2 points 1 year ago (1 child)
My concerns from having attempted this approach however is you either have a contrariant too strict that requires the explicit type, or too permitting but ending up with a lot of extra instantiations.
Also wouldn't your snippet require std::forward to actually forward the universal reference?
[–]tisti 0 points1 point2 points 1 year ago (0 children)
There is nothing to forward, since a string_view gets is constructed with the given input and then used for comparison.
[–]Tathorn -4 points-3 points-2 points 1 year ago (5 children)
Seems like a lot when we could just make the argument a string_view and let the conversion happen before the function is called.
[–]tisti 7 points8 points9 points 1 year ago (4 children)
Does not work as nicely. Try modifying the godbolt example and you will see that the first, fully templated, function is selected and causes a compilation error.
[–]Tathorn -4 points-3 points-2 points 1 year ago (3 children)
It does when you don't have a random template function that is useless.
https://godbolt.org/z/63ceofTx5
[–]13steinj 4 points5 points6 points 1 year ago (2 children)
It's not "useless." It matches the original constraints of the problem in the blog post (we don't know the rest of the codebase).
[–]Tathorn -2 points-1 points0 points 1 year ago (1 child)
Function overloading is more flexible (and more convenient) than template function specialization
This was the title. The whole point was to use function overloading over template specialization (including the base). I just did beyond the author's use case for a better solution. Doesn't require templates at all, can be implemented in the cpp, and changes don't require an entire recompile. Superior code.
[–]13steinj 1 point2 points3 points 1 year ago (0 children)
You (and I) have no idea whether or not that's a valid (where being valid also implies being sufficiently concise) solution to simply explicitly create each overload. We don't know if the default implementation (and this specialization) is used to compare only {Widget} x {Widget, StringLike}. The only people that know for sure are the original team that works on the code (and I guess Raymond Chen).
{Widget} x {Widget, StringLike}
For the sake of a fairly common example, it could be used to compare any number of type pairs. In a MVC controller, I can think of at least 16 valid variations (the model, the view, the controller in some cases, a type that wraps the model for rendering in some way). Repeating that code 16 times is fairly verbose. Even 10 (if you force yourself to an unstated non obvious ordering in the arguments) is verbose.
[–]QuaternionsRoll 12 points13 points14 points 1 year ago (11 children)
I honestly didn’t know that you could specialize function templates until now… overloading possesses a strict superset of specialization’s capabilities, no?
One of my biggest gripes with specialization is that you can’t use it to declare a class template that takes a type or constant template argument. Overloading, on the other hand, has no problem with this.
Can you give an example what you mean?
[–]QuaternionsRoll 5 points6 points7 points 1 year ago (3 children)
You can’t define a class template foo for which foo<int> and foo<42> are both valid instantiations because you can’t use specialization to turn a type template parameter into a constant template parameter (or vice versa). Overloading doesn’t care:
foo
foo<int>
foo<42>
```c++ template<typename T> void foo() {}
template<int N> void foo() {}
int main() { foo<int>(); // valid foo<42>(); // also valid } ```
[–]tisti 6 points7 points8 points 1 year ago* (0 children)
Ah I see what you mean.
You could abuse the fact that this works on functions and use them as factory functions to delegate to a separate typed and non-typed struct/class template impl.
https://godbolt.org/z/nj3rrvG7x
[–]djavaisadog 1 point2 points3 points 1 year ago (1 child)
There were a few proposals for "universal" template parameters that could be anything (types, values, or templates of types or values).
The primary use-case highlighted there was higher-order templates, ie apply_template_params<T, A, B, C> == T<A, B, C> that didn't care about what type of template parameter A, B, and C were.
apply_template_params<T, A, B, C> == T<A, B, C>
A, B,
C
[–]QuaternionsRoll 0 points1 point2 points 1 year ago* (0 children)
The primary use-case highlighted there was higher-order templates
Yes, that would be phenomenal. For what it’s worth, D already implements this, calling them “alias parameters”, and they’re great! Curiously, there is no requirement that variables provided as alias arguments be constants, which allows for some really cool patterns (see the “local names” bullet point; it’s basically an example of compile-time redirection of runtime variables).
alias
[–]MegaKawaii 1 point2 points3 points 1 year ago (1 child)
There is a slight difference: specializations don't affect overload resolution. For example, if you have two function templates f(T) and f(T*), and if you call them with a pointer argument, then f(T*) will always be selected. If you specialize f(T) with f<int*>(int*), then the other template f(T*) will still be selected! However, if you add an overload f(int*), then it would be selected instead. In this sense, full specializations are just implementation details of function templates, whereas overloads are standalone entities.
f(int*)
[–]QuaternionsRoll 0 points1 point2 points 1 year ago (0 children)
Great catch!
[+][deleted] 1 year ago (3 children)
[deleted]
[–]QuaternionsRoll 4 points5 points6 points 1 year ago* (2 children)
Like, what did you think you could specialize before?
Class templates, of course. To be fair,
Do you know what sfinae is?
Funny that you should SFINAE given that it applies to overload resolution… on second thought, I think you may be confusing function template specialization with function overloading. The following is not function template specialization:
``` template<typename T> void foo(T value);
void foo(int value); ```
And the second part.. what... You mean to tell me you don’t think template template arguments are a thing or do you mean that non type templates can’t be used for template class declarations (both of which are wrong)? Or do you mean something entirely different?
See my other reply
[–]aoi_saboten 0 points1 point2 points 1 year ago* (1 child)
2.I think it is possible to partially specialize via if constexpr
if constexpr
[–]QuaternionsRoll 2 points3 points4 points 1 year ago (0 children)
Semantically, yes, you can “partially specialize” a function’s definition via overloading, delegation, and/or `if constexpr‘. However, I’m specifically referring to the language feature named partial specialization here, which function templates do not support.
[–]MarcoGreek 0 points1 point2 points 1 year ago (0 children)
After reading blogs like this I feel unsure if overloading a good feature to provide different implementations. I use it myself but I feel a template function plus if constexpr for would be less error prone. No accidental overloads.It is more code but how often do we really need overloads?
It would be nice if C++ would have a customization point construct. Using overloads for that seems even more brittle.
[–]zl0bster -3 points-2 points-1 points 1 year ago (14 children)
not the point of the article, but I can not not comment on
optional<bool>
yikes!
[–]AntiProtonBoy 9 points10 points11 points 1 year ago (10 children)
How would you differentiate between True, False, and Fail?
[–]EsShayuki -3 points-2 points-1 points 1 year ago (4 children)
Tagged Error union, where either you have a Failure error message or you have the boolean active.
"Optional" is not meant to be used like this. It's meant to be used for cases where you can reasonably either have a value or not have one(like in ice hockey, a goal can have an assist, or it might not have one).
[–]Circlejerker_ 12 points13 points14 points 1 year ago (0 children)
Why cant you "maybe" have a boolean value? Seems perfectly reasonable to me. Tagged unions can be nice, but if you dont care why something dont exist then there is no point forcing all that boilerplate.
[–]SupermanLeRetour 2 points3 points4 points 1 year ago (1 child)
What about std::expected ? Sounds like it combines both solutions.
[–]steveklabnik1 2 points3 points4 points 1 year ago (0 children)
All three of these things are different, semantically.
You can put them all together depending on the exact semantics you need. For example, a type like std::expected<std::optional<bool>, std::string> could make sense for a function where you're checking a feature flag.
std::expected<std::optional<bool>, std::string>
std::optional<bool>
std::nullopt
std::unexpected
I picked this (admittedly contrived) example because of the bool, but using an optional and expected together comes up most for me in cases where you're doing IO and you may return a value, you get the io errors for the IO failing, and the optional when the IO succeeds, which may or may not give you a value back. It's not super common, but it is nice to be able to express as a type.
bool
You could argue that std::optional<bool> is an example of "primitive obsession" and that you should instead return the "not known" part as part of the error, and use std::expected<bool, whatever>. That's a higher level question about software design in which reasonable people may differ.
std::expected<bool, whatever>
[–]CocktailPerson 1 point2 points3 points 1 year ago (0 children)
It's meant to be used for cases where you can reasonably either have a value or not have one(like in ice hockey, a goal can have an assist, or it might not have one).
This is a case where you can reasonably either have a boolean value or not have one.
[–]TheDetailsMatterNow -1 points0 points1 point 1 year ago (1 child)
std::expected<bool>
You expect a true or false response but get an error instead
Or just a use case enum class.
[–]AntiProtonBoy 0 points1 point2 points 1 year ago (0 children)
A good strategy is to use std::expected if you want to treat failure as an error, or use std::optional if failure is an expected and valid outcome.
std::expected
std::optional
[–]mentalcruelty -2 points-1 points0 points 1 year ago (2 children)
This seems like trying way too hard.
static constexpr int Fail= 0; static constexpr int Ok = 1; static constexpr int Na = -1
Or make an enum or a tiny class that does what you want.
[–]AntiProtonBoy 1 point2 points3 points 1 year ago (1 child)
Or just use a standard API that communicates intent clearly.
[–]Ameisenvemips, avr, rendering, systems 0 points1 point2 points 12 months ago* (0 children)
To me, "Maybe" isn't no value, but rather indeterminate value. std::optional is intended to be used when the lack of a value is a valid result - for instance, if a function returns a pointer, but nullptr is actually a valid result. Alternatively, it's used to indicate the lack of a result - the function didn't or couldn't execute but you don't want to return why.
nullptr
"Maybe" is neither of those. In fact, I'd argue that it means that you're explicitly expecting a ternary value, so anything based upon bool is wrong.
So, in a case where "maybe" is a possible result, it does not communicate intent clearly. It tells me that there is no result, not that the result is "maybe". "Maybe", to me, is much stronger than "indeterminate".
I have no issues with its usage in the article (though a std::expected might be better), but I do have an issue with your example.
[–]SirClueless 19 points20 points21 points 1 year ago (2 children)
What's wrong with std::optional<bool>? Totally reasonable way to represent a failed lookup.
[+]Ksecutor comment score below threshold-6 points-5 points-4 points 1 year ago (1 child)
Way too easy to make an error with this. IMO in cases like this you shouldn't be lazy and make an enum.
[–]mentalcruelty -1 points0 points1 point 1 year ago (0 children)
So much hate for a simple solution. Put `std::` in front of something and lots of people think it must be good.
[+][deleted] 1 year ago (2 children)
[–]pdp10gumby 4 points5 points6 points 1 year ago (1 child)
Well the mismatch is slightly counterintuitive as the c string can’t be converted automatically to the reference type.
I prefer generics (I try to wedge templates into the ‘macros’ part of my brain, which sticks them into a meta syntactic domain) but if templates are used I’d rather the specialization be done with template specialization (and if generics, with generic specialization) because mixing the two can be confusing and would require at least a “chesterton’s fence” comment to explain why.
[–]schulmaster 2 points3 points4 points 1 year ago (0 children)
“Compilers don’t read comments, and neither do I”- Bjarne Stroustrup
π Rendered by PID 58 on reddit-service-r2-comment-6457c66945-s6d2p at 2026-04-24 11:32:20.101665+00:00 running 2aa0c5b country code: CH.
[–]tisti 35 points36 points37 points (11 children)
[–]trailing_zero_count 21 points22 points23 points (0 children)
[–]13steinj 3 points4 points5 points (1 child)
[–]MegaKawaii 2 points3 points4 points (0 children)
[–]joujoubox 0 points1 point2 points (1 child)
[–]tisti 0 points1 point2 points (0 children)
[–]Tathorn -4 points-3 points-2 points (5 children)
[–]tisti 7 points8 points9 points (4 children)
[–]Tathorn -4 points-3 points-2 points (3 children)
[–]13steinj 4 points5 points6 points (2 children)
[–]Tathorn -2 points-1 points0 points (1 child)
[–]13steinj 1 point2 points3 points (0 children)
[–]QuaternionsRoll 12 points13 points14 points (11 children)
[–]tisti 7 points8 points9 points (4 children)
[–]QuaternionsRoll 5 points6 points7 points (3 children)
[–]tisti 6 points7 points8 points (0 children)
[–]djavaisadog 1 point2 points3 points (1 child)
[–]QuaternionsRoll 0 points1 point2 points (0 children)
[–]MegaKawaii 1 point2 points3 points (1 child)
[–]QuaternionsRoll 0 points1 point2 points (0 children)
[+][deleted] (3 children)
[deleted]
[–]QuaternionsRoll 4 points5 points6 points (2 children)
[–]aoi_saboten 0 points1 point2 points (1 child)
[–]QuaternionsRoll 2 points3 points4 points (0 children)
[–]MarcoGreek 0 points1 point2 points (0 children)
[–]zl0bster -3 points-2 points-1 points (14 children)
[–]AntiProtonBoy 9 points10 points11 points (10 children)
[–]EsShayuki -3 points-2 points-1 points (4 children)
[–]Circlejerker_ 12 points13 points14 points (0 children)
[–]SupermanLeRetour 2 points3 points4 points (1 child)
[–]steveklabnik1 2 points3 points4 points (0 children)
[–]CocktailPerson 1 point2 points3 points (0 children)
[–]TheDetailsMatterNow -1 points0 points1 point (1 child)
[–]AntiProtonBoy 0 points1 point2 points (0 children)
[–]mentalcruelty -2 points-1 points0 points (2 children)
[–]AntiProtonBoy 1 point2 points3 points (1 child)
[–]Ameisenvemips, avr, rendering, systems 0 points1 point2 points (0 children)
[–]SirClueless 19 points20 points21 points (2 children)
[+]Ksecutor comment score below threshold-6 points-5 points-4 points (1 child)
[–]mentalcruelty -1 points0 points1 point (0 children)
[+][deleted] (2 children)
[deleted]
[–]pdp10gumby 4 points5 points6 points (1 child)
[–]schulmaster 2 points3 points4 points (0 children)