-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
T.70 Prefer if constexpr to function template overloading #2099
Comments
The overload mentioned is useful. The types are not necessarily the same, and combining it down to a single function isn't necessarily useful either. Overloading does come with a cost, but it's an acceptable cost in most cases, and often will be cleaned up during compile so runtime cost is usually negligible if any. Let's not create practices that needlessly shill all things towards one methodology/type usage like in your examples. |
How?
Could you clarify what you mean here?
(I don't think you mean "shill" here). The rationale given makes sense, it's not "needlessly". |
At least in my team the accepted style is to prefer (tag-dispatched) overloading where possible, specifically to "keep functions short and simple" - we've seen an innocuous I mostly see successful |
Sorry for delay...
Overloads handle different methods of calling so you can distinguish between how it is called and what parameter types are used in the call. Yes, templates generalize some of that, but not by much.
The In fact, the
The rational is pushing a specific design method that isn't necessarily very good. So yes it is needlessly shilling a specific methodology/practice. That's not to say the pattern does make sense in some cases; however, it does not make sense in sufficient cases to be a standard here in the guide as it will end up leading to a lot of bad code because "following the guidelines". |
How is that not true for the variadic template? The number of types in the parameter pack tells you how it was called, and all the types are available.
Do you mean the "bad" one as shown can have better performance? How? It does the same thing. If you mean it could be implemented differently to have better performance, why couldn't that also be done in the "good" example's I don't follow your reasoning at all, sorry. |
The Now if you consider the best operation time, the
So you've just made code perform worse even in the best possible code path all because of following a specific design pattern and always use variadic arguments. At minimum you've increased compile time if not also increasing run-time. |
I have no idea what you're talking about. The first overload just returns its argument, that's not "a straight forward approach" to calculating the minimum of two values. It's dumb, and exists only because you have to terminate the recursion, which requires a separate function when using the "bad" style.
It uses
Adding another It's trivial to show that the codegen is identical: https://godbolt.org/z/W6jf87qqz
What proposed fix? I have no idea what you're talking about. Again, the codegen for the "good" and "bad" examples is identical. The claimed difference is readability and maintenance. Your claims about performance are bogus. Have you even read the examples? |
And the same two pieces of code optimized (but with inlining disabled so it doesn't just get optimized to |
Are you confused by At least in this case, the two functions should have identical codegen, except that the "good" example keeps all the logic in a single function, eliminating overload resolution. |
There is always a penalty. Its just a matter of where. |
So where is the penalty here? |
The penalty is that you will have to split this function up once it becomes too large. In that case, you would use overloading with tag dispatch possibly. Or alternatively, you could call other functions by name from inside of Anyhow, that's only a penalty when your function grows, in the form of some refactoring work. Other than that, I see it as strictly better than any other option:
|
Just to clarify my personal stance: I totally agree with using constexpr if instead of overloading for most situations and especially for the example at hand to implement the base case of a recursive function. I am a bit sceptical for cases, where two versions of a function handle fundamentally different Parameter types. Like "minimum of N separate parameters" and "minimum of the elements in a range". As preconditions, run-time complexity and maybe even other properties like constexprness and noexceptnes may vary significantly between those versions I think it's better to separate them behind separate function interfaces that can also be documented separately. So I'm not sure if I want the compiler to warn on any overload set of function templates. The counterargument is of course that you probably should give those functions different names anyway if they are so different. I would have to look at more real-world cases to form an well founded opinion on there matter. |
@MikeGitb that's not why we have two functions. The first overload is just a base case that we need for a single argument. Both functions are part of a variadic
There is an argument to be had that creating separate functions assists in creating conditional What I'm trying to say is that |
I know, that is exactly what I said in my first paragraph.
I disagree, but I don't think it's off big relevance for this rule one way or the other, so let's not get hung up on it. |
Here is a suggestion for a rule which encourages the use of
if constexpr
.Not only do we repeat ourselves and keep logic less fragmented, we also save on compile times typically, because overload resolution is very expensive.
I'm not so sure if the recursive
min
example demonstrates it best, perhaps someone else can think of a better one.T.70 Prefer
if constexpr
to function template overloading for short functionsReason
Example, good
Example, bad
Note
Long function templates are difficult to read and understand. Consider F.3: Keep functions short and simple
Enforcement
Flag short, overloaded function templates.
The text was updated successfully, but these errors were encountered: