Why don't more mainstream statically typed languages support function/method overloading by return type? I can't think of any that do. It seems no less useful or reasonable than supporting overload by parameter type. How come it's so much less popular?

- 8,356
- 19
- 50
- 61

- 67,514
- 53
- 213
- 334
-
2possible duplicate of [Overload a C++ function according to the return value](http://stackoverflow.com/questions/226144/overload-a-c-function-according-to-the-return-value) – May 29 '13 at 13:54
-
@user195488 this is not a duplicate because it's a general question. – Flimtix Mar 03 '22 at 11:59
14 Answers
Contrary to what others are saying, overloading by return type is possible and is done by some modern languages. The usual objection is that in code like
int func();
string func();
int main() { func(); }
you can't tell which func()
is being called. This can be resolved in a few ways:
- Have a predictable method to determine which function is called in such a situation.
- Whenever such a situation occurs, it's a compile-time error. However, have a syntax that allows the programmer to disambiguate, e.g.
int main() { (string)func(); }
. - Don't have side effects. If you don't have side effects and you never use the return value of a function, then the compiler can avoid ever calling the function in the first place.
Two of the languages I regularly (ab)use overload by return type: Perl and Haskell. Let me describe what they do.
In Perl, there is a fundamental distinction between scalar and list context (and others, but we'll pretend there are two). Every built-in function in Perl can do different things depending on the context in which it is called. For example, the join
operator forces list context (on the thing being joined) while the scalar
operator forces scalar context, so compare:
print join " ", localtime(); # printed "58 11 2 14 0 109 3 13 0" for me right now
print scalar localtime(); # printed "Wed Jan 14 02:12:44 2009" for me right now.
Every operator in Perl does something in scalar context and something in list context, and they may be different, as illustrated. (This isn't just for random operators like localtime
. If you use an array @a
in list context, it returns the array, while in scalar context, it returns the number of elements. So for example print @a
prints out the elements, while print 0+@a
prints the size.) Furthermore, every operator can force a context, e.g. addition +
forces scalar context. Every entry in man perlfunc
documents this. For example, here is part of the entry for glob EXPR
:
In list context, returns a (possibly empty) list of filename expansions on the value of
EXPR
such as the standard Unix shell/bin/csh
would do. In scalar context, glob iterates through such filename expansions, returning undef when the list is exhausted.
Now, what's the relation between list and scalar context? Well, man perlfunc
says
Remember the following important rule: There is no rule that relates the behavior of an expression in list context to its behavior in scalar context, or vice versa. It might do two totally different things. Each operator and function decides which sort of value it would be most appropriate to return in scalar context. Some operators return the length of the list that would have been returned in list context. Some operators return the first value in the list. Some operators return the last value in the list. Some operators return a count of successful operations. In general, they do what you want, unless you want consistency.
so it's not a simple matter of having a single function, and then you do simple conversion at the end. In fact, I chose the localtime
example for that reason.
It's not just the built-ins that have this behavior. Any user can define such a function using wantarray
, which allows you to distinguish between list, scalar, and void context. So, for example, you can decide to do nothing if you're being called in void context.
Now, you may complain that this isn't true overloading by return value because you only have one function, which is told the context it's called in and then acts on that information. However, this is clearly equivalent (and analogous to how Perl doesn't allow usual overloading literally, but a function can just examine its arguments). Moreover, it nicely resolves the ambiguous situation mentioned at the beginning of this response. Perl doesn't complain that it doesn't know which method to call; it just calls it. All it has to do is figure out what context the function was called in, which is always possible:
sub func {
if( not defined wantarray ) {
print "void\n";
} elsif( wantarray ) {
print "list\n";
} else {
print "scalar\n";
}
}
func(); # prints "void"
() = func(); # prints "list"
0+func(); # prints "scalar"
(Note: I may sometimes say Perl operator when I mean function. This is not crucial to this discussion.)
Haskell takes the other approach, namely to not have side effects. It also has a strong type system, and so you can write code like the following:
main = do n <- readLn
print (sqrt n) -- note that this is aligned below the n, if you care to run this
This code reads a floating point number from standard input, and prints its square root. But what is surprising about this? Well, the type of readLn
is readLn :: Read a => IO a
. What this means is that for any type that can be Read
(formally, every type that is an instance of the Read
type class), readLn
can read it. How did Haskell know that I wanted to read a floating point number? Well, the type of sqrt
is sqrt :: Floating a => a -> a
, which essentially means that sqrt
can only accept floating point numbers as inputs, and so Haskell inferred what I wanted.
What happens when Haskell can't infer what I want? Well, there a few possibilities. If I don't use the return value at all, Haskell simply won't call the function in the first place. However, if I do use the return value, then Haskell will complain that it can't infer the type:
main = do n <- readLn
print n
-- this program results in a compile-time error "Unresolved top-level overloading"
I can resolve the ambiguity by specifying the type I want:
main = do n <- readLn
print (n::Int)
-- this compiles (and does what I want)
Anyway, what this whole discussion means is that overloading by return value is possible and is done, which answers part of your question.
The other part of your question is why more languages don't do it. I'll let others answer that. However, a few comments: the principle reason is probably that the opportunity for confusion is truly greater here than in overloading by argument type. You can also look at rationales from individual languages:
Ada: "It might appear that the simplest overload resolution rule is to use everything - all information from as wide a context as possible - to resolve the overloaded reference. This rule may be simple, but it is not helpful. It requires the human reader to scan arbitrarily large pieces of text, and to make arbitrarily complex inferences (such as (g) above). We believe that a better rule is one that makes explicit the task a human reader or a compiler must perform, and that makes this task as natural for the human reader as possible."
C++ (subsection 7.4.1of Bjarne Stroustrup's "The C++ Programming Language"): "Return types are not considered in overload resolution. The reason is to keep resolution for an individual operator or function call context-independent. Consider:
float sqrt(float);
double sqrt(double);
void f(double da, float fla)
{
float fl = sqrt(da); // call sqrt(double)
double d = sqrt(da); // call sqrt(double)
fl = sqrt(fla); // call sqrt(float)
d = sqrt(fla); // call sqrt(float)
}
If the return type were taken into account, it would no longer be possible to look at a call of sqrt()
in isolation and determine which function was called." (Note, for comparison, that in Haskell there are no implicit conversions.)
Java (Java Language Specification 9.4.1): "One of the inherited methods must be return-type-substitutable for every other inherited method, or else a compile-time error occurs." (Yes, I know this doesn't give a rationale. I'm sure the rationale is given by Gosling in "the Java Programming Language". Maybe someone has a copy? I bet it's the "principle of least surprise" in essence.) However, fun fact about Java: the JVM allows overloading by return value! This is used, for example, in Scala, and can be accessed directly through Java as well by playing around with internals.
PS. As a final note, it is actually possible to overload by return value in C++ with a trick. Witness:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
-
Great post, but you might want to clarify what reading is (String -> something). – Thomas Eding Jan 24 '10 at 08:41
-
C++ also let's you overload by const/not const returned value. http://stackoverflow.com/questions/251159/what-is-the-use-of-const-overloading-in-c – geon Oct 30 '10 at 10:31
-
3For your last trick with overloading the coercion operators, the "cout" line works sometimes, but almost any change I make to the code makes it give "ambiguous overload for 'operator<<'". – Steve Oct 31 '10 at 16:05
-
1The approach I would favor would be to require that one overload be marked as "preferred"; the compiler would start by binding using only preferred overloads, and then determine if any non-preferred overloads would be an improvement. Among other things, suppose types `Foo` and `Bar` support bidirectional conversion, and a method uses type `Foo` internally but returns type `Bar`. If such method is called by code which will immediately coerce the result to type `Foo`, using the `Bar` return type might work, but the `Foo` one would be better. BTW, I'd also like to see a means by which... – supercat Dec 15 '12 at 22:48
-
...a method could designate what type should be used in a construct like `var someVar = someMethod();` (or else designate that its return should not be used in such fashion). For example, a family of types that implements a Fluent interface might benefit from having mutable and immutable versions, so `var thing2 = thing1.WithX(3).WithY(5).WithZ(9);` would have `WithX(3)` copy `thing1` to a mutable object, mutate X, and return that mutable object; `WithY(5)` would mutate Y and return the same object; likewise `WithZ(9). Then the assignment would convert to an immutable type. – supercat Dec 15 '12 at 22:55
-
If one could overload by return type in the situations where the compiler could tell the type would be immediately converted to the immutable type, the `WithWhatever` method could know that the mutable object had never been exposed to the outside world and could thus safely encapsulate it in a read-only wrapper without having to make an extra copy of its contents. – supercat Dec 15 '12 at 22:58
-
I wonder if there is a way to avoid having people create lvavlues of the "struct function". – Trevor Hickey Dec 19 '13 at 11:41
-
Lambda expressions in C# are an example of a *literal* (not a function) that is overloaded on its expression type. If a lambda expression is used in a context that expects an `Action` or `Func` (i.e. executable code), the lambda expression will evaluate to executable code (essentially an anonymous method). If a lambda expression is used in a context that expects an `Expression` (think *Abstract Syntax Tree*), the lambda expression will evaluate to an *un-evaluated abstract representation of the code in the body*. – Jörg W Mittag Feb 29 '20 at 23:07
-
This is used to great effect in LINQ Queries: you can pass the exact same lambda expression as a predicate to filter an array or a database. In the case of the array, you are using the LINQ-to-Objects LINQ provider, which expects executable code, and thus your lambda will evaluate to a `Func
`, which will be executed to filter the elements of the in-memory array. However, in the case of the DB, you are using (for example) the LINQ-to-SQL provider, which takes the lambda as an un-evaluated `Expression`, examines its contents and translates it into SQL, which it sends to the DB. – Jörg W Mittag Feb 29 '20 at 23:09 -
3The Ada rationale goes on to say "We conclude that the use of the function result type in overload resolution is methodologically the better choice, and one that enhances the freedom of the programmer to write natural, comprehensible expressions." This would have been to more appropriate portion to quote. – Carl Reinke Oct 03 '20 at 18:41
-
The Oracle link is broken.. do you happen to have a replacement by any chance? I'm eager to read it.. – elect Nov 11 '22 at 11:47
-
@elect: The Internet archive should help you with these questions in general. See https://web.archive.org/web/20080906155609/http://today.java.net/pub/a/today/2008/07/31/return-type-based-method-overloading.html – A. Rex Nov 11 '22 at 23:42
If functions were overloaded by the return type and you had these two overloads
int func();
string func();
there is no way the compiler could figure out which of those two functions to call upon seeing a call like this
void main()
{
func();
}
For this reason, language designers often disallow return-value overloading.
Some languages (such as MSIL), however, do allow overloading by return type. They too face the above difficulty of course, but they have workarounds, for which you'll have to consult their documentation.

- 35,511
- 22
- 84
- 118
-
5A minor quibble (your answer gives a very clear, understandable rationale): it's not that there's no way; it's just that the ways would be clumsy and more painful than most people would like. For example, in C++, the overload would likely have been resolvable using some ugly cast syntax. – Michael Burr Jan 14 '09 at 17:25
-
But Michael, how could a call like the one above (func();) be resolved without the user himself helping the compiler with additional hints? I don't think it's possible at all. – G S Jan 14 '09 at 17:41
-
The return value is not used anywhere, so it doesn't matter which one of the two will be called. In fact, your entire main() function is a no-op. – Jörg W Mittag Jan 14 '09 at 17:55
-
1@Frederick - I agree that the user would need to provide more information to the compiler for this to work (note I am *not* saying that it does work - just that it could if language designers thought it was valuable). In C++, the way they probably would have done it is by using a cast of some sort. – Michael Burr Jan 14 '09 at 18:03
-
3@Jörg W Mittag: You don't see what the functions do. They could easily have *different* side effects. – A. Rex Jan 14 '09 at 18:12
-
If they had side effects, they wouldn't be functions, would they? I mean, that's pretty much the *definition* of "function": having no side effects. At the *very least*, they would need to have different return types, something like `IO int func();` or `IO string func();`. – Jörg W Mittag Jan 14 '09 at 19:45
-
3@Jörg - in most mainstream programming languages (C/C++, C#, Java, etc.) functions commonly have side-effects. In fact, I'd guess that functions with side effects are at least as common as those without. – Michael Burr Jan 14 '09 at 21:20
-
1I don't know much about C or C++, but I definitely know that functions in C# and Java cannot have side effects, because C# and Java don't even *have* functions. They have methods, precisely *because* can methods can have side effects. – Jörg W Mittag Jan 15 '09 at 00:32
-
1Jörg, your view on the matter is very strange. can you prove that (methods being functions with side effects)? – Johannes Schaub - litb Jan 15 '09 at 13:47
-
No, I can't, because I never said that. Please don't put words in my mouth. – Jörg W Mittag Jan 15 '09 at 21:56
-
6Jumping in late here, but in some contexts "function" has the narrow definition of (essentially) "a method with no side effects". More colloquially, "function" is often used interchangeably with "method" or "subroutine". Jorg is either being rigorous or pedantic, depending on your point of view :) – AwesomeTown Feb 25 '09 at 04:34
-
3Jumping in even later, some points of view might use adjectives other than rigorous or pedantic – Patrick McDonald Jun 26 '12 at 11:27
-
1Your example is correct. In your example you're calling `func()` without return type, so if return types would matter, there should be a `void func() { ... }` being declared, which is called in that case. In other words: The signature would have to be more strict - and void is an (empty) return type as well. So in the compiler should emit an error, if a void function is missing, or emit a message that the call is ambiguous. – Matt Apr 21 '15 at 08:35
In such a language, how would you resolve the following:
f(g(x))
if f
had overloads void f(int)
and void f(string)
and g
had overloads int g(int)
and string g(int)
? You would need some kind of disambiguator.
I think the situations where you might need this would be better served by choosing a new name for the function.

- 951,095
- 183
- 1,149
- 1,285
-
2The regular kind of overloading can result in ambiguities as well. I think these are normally resolved by counting the number of casts required, but this doesn't always work. – Jay Conrod Jan 14 '09 at 06:52
-
1yes, standard conversions are ranked into exact match, promotion and conversion: void f(int); void f(long); f('a'); calls f(int), because that's only a promotion, while converting to long is a conversion. void f(float); void f(short); f(10); would require conversion for both: the call is ambiguous. – Johannes Schaub - litb Jan 14 '09 at 07:58
-
-
Upvote, the interaction of parameter type overloading and return type overloading isn't addressed in Rex's post. Very good point. – Joseph Garvin Oct 31 '10 at 23:11
-
-
2Were I designing a language, my rule would be that for any overloaded function, each parameter signature must have a one return-type designated as the default; a compiler would start by assuming every function call would use the default type. Once that was done, however, in every situation where a function's return value was immediately cast or coerced to something else, the compiler would check for an overload whose parameter signature is identical, but whose return type is a better match (or possibly void). I would probably also impose an "override-one--override-all" rule for such overloads. – supercat Jan 05 '12 at 22:05
-
I would think that such rules would allow for some useful optimizations in many scenarios, without introducing problematic ambiguities, though to be sure some other language features would be needed to make them most useful including the ability to distinguish the case where the only thing done with the return value was to access some particular field. – supercat Jan 05 '12 at 22:11
-
Why java not allowing different return in inheritance too? ( I know about overriding but why java not applying hiding concept ) ? here is complete question.http://stackoverflow.com/questions/35957019/why-return-type-of-same-named-method-should-be-same-in-sub-class-java – Asif Mushtaq Mar 12 '16 at 12:06
To steal a C++ specific answer from another very similar question (dupe?):
Function return types don't come into play in overload resolution simply because Stroustrup (I assume with input from other C++ architects) wanted overload resolution to be 'context independent'. See 7.4.1 - "Overloading and Return Type" from the "C++ Programming Language, Third Edition".
The reason is to keep resolution for an individual operator or function call context-independent.
They wanted it to be based only on how the overload was called - not how the result was used (if it was used at all). Indeed, many functions are called without using the result or the result would be used as part of a larger expression. One factor that I'm sure came into play when they decided this was that if the return type was part of the resolution there would be many calls to overloaded functions that would need to be resolved with complex rules or would have to have the compiler throw an error that the call was ambiguous.
And, Lord knows, C++ overload resolution is complex enough as it stands...

- 1
- 1

- 333,147
- 50
- 533
- 760
In haskell it's possible even though it doesn't have function overloading. Haskell uses type classes. In a program you could see:
class Example a where
example :: Integer -> a
instance Example Integer where -- example is now implemented for Integer
example :: Integer -> Integer
example i = i * 10
Function overloading itself is not so popular. Mostly languages I've seen with it are C++, perhaps java and/or C#. In all dynamic languages it's a shorthand for:
define example:i
↑i type route:
Integer = [↑i & 0xff]
String = [↑i upper]
def example(i):
if isinstance(i, int):
return i & 0xff
elif isinstance(i, str):
return i.upper()
Therefore there's no much point in it. Most people aren't interested whether language can help you drop a single line per where ever you use it.
Pattern matching is somewhat similar to function overloading, and I guess sometimes work similarly. It's not common though because it is useful only for few programs and is tricky to implement on most of languages.
You see there's infinitely many other better easier-to-implement features to implement into the language, including:
- Dynamic typing
- Internal support for lists, dictionaries and unicode strings
- Optimizations (JIT, type inferencing, compiling)
- Integrated deployment tools
- Library support
- Community support and gathering places
- Rich standard libraries
- Good syntax
- Read eval print loop
- Support for reflective programming

- 24,645
- 16
- 59
- 83
-
3Haskell has overloading. Type classes is the language feature that is used to define overloaded functions. – Lii Apr 19 '12 at 16:12
Good answers! A.Rex's answer in particular is very detailed and instructive. As he points out, C++ does consider user-supplied type-conversion operators when compiling lhs = func();
(where func is really the name of a struct). My workaround is a bit different - not better, just different (although it's based on the same basic idea).
Whereas I had wanted to write...
template <typename T> inline T func() { abort(); return T(); }
template <> inline int func()
{ <<special code for int>> }
template <> inline double func()
{ <<special code for double>> }
.. etc, then ..
int x = func(); // ambiguous!
int x = func<int>(); // *also* ambiguous!? you're just being difficult, g++!
I ended up with a solution that uses a parameterized struct (with T = the return type):
template <typename T>
struct func
{
operator T()
{ abort(); return T(); }
};
// explicit specializations for supported types
// (any code that includes this header can add more!)
template <> inline
func<int>::operator int()
{ <<special code for int>> }
template <> inline
func<double>::operator double()
{ <<special code for double>> }
.. etc, then ..
int x = func<int>(); // this is OK!
double d = func<double>(); // also OK :)
A benefit of this solution is that any code which includes these template definitions can add more specializations for more types. Also you can do partial specializations of the struct as needed. For example, if you wanted special handling for pointer types:
template <typename T>
struct func<T*>
{
operator T*()
{ <<special handling for T*>> }
};
As a negative, you can't write int x = func();
with my solution. You have to write int x = func<int>();
. You have to explicitly say what the return type is, rather than asking the compiler to suss it out by looking at type conversion operators. I would say that "my" solution and A.Rex's both belong in a pareto-optimal front of ways to tackle this C++ dilemma :)

- 204
- 1
- 9
if you want to overload methods with different return types, just add a dummy parameter with default value to allow the overload execution, but don't forget the parameter type should be different so the overload logic works next is an e.g on delphi:
type
myclass = class
public
function Funct1(dummy: string = EmptyStr): String; overload;
function Funct1(dummy: Integer = -1): Integer; overload;
end;
use it like this
procedure tester;
var yourobject : myclass;
iValue: integer;
sValue: string;
begin
yourobject:= myclass.create;
iValue:= yourobject.Funct1(); //this will call the func with integer result
sValue:= yourobject.Funct1(); //this will call the func with string result
end;

- 849
- 13
- 25
-
That's a terrible idea. Don't introduce dummy parameters, that's a big code smell. Instead, choose different names, or choose a return type that can act like, or is a discriminated union or something. – Abel Dec 22 '19 at 21:47
-
@Abel what you are suggesting is actually the terrible idea, because that the whole idea is about this dummy parameter, and it is named like that to make it clear for the developer that this parameter is dummy and should be ignored, also in case you don't know the dummy parameters with default values are used in many libraries, VCL in delphi, and many IDEs, e.g in delphi you can see it in the sysutils unit in SafeLoadLibrary... – ZORRO_BLANCO Jan 15 '20 at 10:03
-
There are certainly scenarios where dummy parameters are useful, like in lambdas in map or fold operations, or when implementing an interface. But for the mere sake of creating an overload, no, I beg to disagree. There's no need and it's noise that programmers can live without. – Abel Jan 21 '20 at 17:26
As already shown - ambiguous calls of a function that differs only by return type introduces ambiguity. Ambiguity induces defective code. Defective code must be avoided.
The complexity driven by the attempt to ambiguity shows that this is not a good hack. Apart from an intellectual exercise - why not use procedures with reference parameters.
procedure(reference string){};
procedure(reference int){};
string blah;
procedure(blah)
-
Because you can't easily reuse the "return" values immediately. You'd have to do each call on a single line, as opposed to `doing(thisVery(deeplyNested(), andOften(butNotAlways()), notReally()), goodCode());` – Adowrath Mar 18 '17 at 21:09
this overloading feature is not hard to manage, if you look at it in a slightly different way. consider the following,
public Integer | String f(int choice){
if(choice==1){
return new string();
}else{
return new Integer();
}}
if a language did return overloading it would allow parameter overloading, but not duplications. this would solve the problem of:
main (){
f(x)
}
because there is only one f(int choice) to choose from.

- 5,632
- 3
- 27
- 47

- 1
In .NET, sometimes we use one parameter to indicate the desired output from a generic result, and then made a conversion to get what we expect.
C#
public enum FooReturnType{
IntType,
StringType,
WeaType
}
class Wea {
public override string ToString()
{
return "Wea class";
}
}
public static object Foo(FooReturnType type){
object result = null;
if (type == FooReturnType.IntType)
{
/*Int related actions*/
result = 1;
}
else if (type == FooReturnType.StringType)
{
/*String related actions*/
result = "Some important text";
}
else if (type == FooReturnType.WeaType)
{
/*Wea related actions*/
result = new Wea();
}
return result;
}
static void Main(string[] args)
{
Console.WriteLine("Expecting Int from Foo: " + Foo(FooReturnType.IntType));
Console.WriteLine("Expecting String from Foo: " + Foo(FooReturnType.StringType));
Console.WriteLine("Expecting Wea from Foo: " + Foo(FooReturnType.WeaType));
Console.Read();
}
Maybe this example could help too:
C++
#include <iostream>
enum class FooReturnType{ //Only C++11
IntType,
StringType,
WeaType
}_FooReturnType;
class Wea{
public:
const char* ToString(){
return "Wea class";
}
};
void* Foo(FooReturnType type){
void* result = 0;
if (type == FooReturnType::IntType) //Only C++11
{
/*Int related actions*/
result = (void*)1;
}
else if (type == FooReturnType::StringType) //Only C++11
{
/*String related actions*/
result = (void*)"Some important text";
}
else if (type == FooReturnType::WeaType) //Only C++11
{
/*Wea related actions*/
result = (void*)new Wea();
}
return result;
}
int main(int argc, char* argv[])
{
int intReturn = (int)Foo(FooReturnType::IntType);
const char* stringReturn = (const char*)Foo(FooReturnType::StringType);
Wea *someWea = static_cast<Wea*>(Foo(FooReturnType::WeaType));
std::cout << "Expecting Int from Foo: " << intReturn << std::endl;
std::cout << "Expecting String from Foo: " << stringReturn << std::endl;
std::cout << "Expecting Wea from Foo: " << someWea->ToString() << std::endl;
delete someWea; // Don't leak oil!
return 0;
}

- 1
-
1It is kind of hackish, and could lead to run-time errors if the user does not properly cast the result, or if the developer does not properly match the return types with the enum. I would recommend using a template-based approach (or generic parameters in C#?) such as in [this answer](https://stackoverflow.com/a/8190426/1057102) – sleblanc Oct 22 '15 at 20:31
For the record, Octave allows different outcome according to return element being scalar vs array.
x = min ([1, 3, 0, 2, 0])
⇒ x = 0
[x, ix] = min ([1, 3, 0, 2, 0])
⇒ x = 0
ix = 3 (item index)
Cf also Singular Value Decomposition.

- 3,778
- 1
- 20
- 19
This one is slightly different for C++; I don't know if it would be considered overloading by return type directly. It is more of a template specialization that acts in the manner of.
util.h
#ifndef UTIL_H
#define UTIL_H
#include <string>
#include <sstream>
#include <algorithm>
class util {
public:
static int convertToInt( const std::string& str );
static unsigned convertToUnsigned( const std::string& str );
static float convertToFloat( const std::string& str );
static double convertToDouble( const std::string& str );
private:
util();
util( const util& c );
util& operator=( const util& c );
template<typename T>
static bool stringToValue( const std::string& str, T* pVal, unsigned numValues );
template<typename T>
static T getValue( const std::string& str, std::size_t& remainder );
};
#include "util.inl"
#endif UTIL_H
util.inl
template<typename T>
static bool util::stringToValue( const std::string& str, T* pValue, unsigned numValues ) {
int numCommas = std::count(str.begin(), str.end(), ',');
if (numCommas != numValues - 1) {
return false;
}
std::size_t remainder;
pValue[0] = getValue<T>(str, remainder);
if (numValues == 1) {
if (str.size() != remainder) {
return false;
}
}
else {
std::size_t offset = remainder;
if (str.at(offset) != ',') {
return false;
}
unsigned lastIdx = numValues - 1;
for (unsigned u = 1; u < numValues; ++u) {
pValue[u] = getValue<T>(str.substr(++offset), remainder);
offset += remainder;
if ((u < lastIdx && str.at(offset) != ',') ||
(u == lastIdx && offset != str.size()))
{
return false;
}
}
}
return true;
}
util.cpp
#include "util.h"
template<>
int util::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoi( str, &remainder );
}
template<>
unsigned util::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoul( str, &remainder );
}
template<>
float util::getValue( const std::string& str, std::size_t& remainder ) {
return std::stof( str, &remainder );
}
template<>
double util::getValue( const std::string& str, std::size_t& remainder ) {
return std::stod( str, &remainder );
}
int util::convertToInt( const std::string& str ) {
int i = 0;
if ( !stringToValue( str, &i, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
throw strStream.str();
}
return i;
}
unsigned util::convertToUnsigned( const std::string& str ) {
unsigned u = 0;
if ( !stringToValue( str, &u, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
throw strStream.str();
}
return u;
}
float util::convertToFloat(const std::string& str) {
float f = 0;
if (!stringToValue(str, &f, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
throw strStream.str();
}
return f;
}
double util::convertToDouble(const std::string& str) {
float d = 0;
if (!stringToValue(str, &d, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to double";
throw strStream.str();
}
return d;
}
This example is not exactly using function overload resolution by return type, however this c++ non object class is using template specialization to simulate function overload resolution by return type with a private static method.
Each of the convertToType
functions are calling the function template stringToValue()
and if you look at the implementation details or algorithm of this function template it is calling getValue<T>( param, param )
and it is returning back a type T
and storing it into a T*
that is passed into the stringToValue()
function template as one of its parameters.
Other than something like this; C++ does not really have a mechanism to have function overloading resolution by return type. There may be other constructs or mechanisms that I'm not aware of that could simulate resolution by return type.

- 7,788
- 2
- 28
- 59
I think this is a GAP in modern C++ definition… why ?
int func();
double func();
// example 1. → defined
int i = func();
// example 2. → defined
double d = func();
// example 3. → NOT defined. error
void main()
{
func();
}
Why can a C++ compiler can not throw an error in example "3" and accept the code in example "1+2" ??

- 311
- 1
- 10
-
Yes, that's what they've been considering at the time for C# (and maybe C++). But while your code is trivial, once you add class hierarchies, virtual methods, abstracts and interfaces, other overloads and, sometimes multiple inheritance, it gets very complex very quickly to decide which method should be resolved. It's a choice of the designers not to go that route,but other languages have decided differently at various levels of success. – Abel Dec 22 '19 at 21:53
Most static languages also now support generics, which would solve your problem. As stated before, without having parameter diffs, there is not way to know which one to call. So if you want to do this, just use generics and call it a day.

- 24,293
- 14
- 43
- 56
-
Not the same thing. How would you handle a function that translates input to an integer, float, bool, or whatever based on how the return type is used? It can't be generalized since you need a special case for each. – Jay Conrod Jan 14 '09 at 06:58
-
See http://www.codeproject.com/KB/cpp/returnoverload.aspx for a clever strategy for "overloading on return type". Basically, instead of defining a function func(), you define a struct func, give it an operator()() and conversions to each appropriate type. – j_random_hacker Jan 14 '09 at 07:33
-
Jay, you define the return type when you call the function. If the inpus are differant, then there is no problem at all. If there are the same, you can have a generic version that may have some logic based on the type using GetType(). – Charles Graham Jan 14 '09 at 10:31