It's sometimes very useful to create a variable of the correct type where you don't want to explicitly specify the type, particulary when the type is a complex one such as std::map<std::string, std::tuple<int, SomeStructure>>
(1). This is the heart of the almost-always-auto guideline.
For cases where you are initialising the variable, you can use:
auto a = 3.14159f; // float.
auto a = function_returning_type(1, 2, 3); // whatever that function returns.
If you don't want to initialise it, you can use decltype
to just define it:
int a;
decltype(a) b; // integer
float c();
decltype(c()) d; // float
That last one is particularly handy if you want to base the type on what some function returns rather than an already existing variable. However, if the only overloads of the function takes a lot of parameters, it appears to require you to provide them:
int a(const char *, int, float);
decltype(a("", 7, 4.2)) b; // okay
decltype(a()) c; // not okay
That second sample gives something like:
error: too few arguments to function ‘int a(const char *, int, float)’
decltype(a()) c;
^
This is despite the fact that the parameters shouldn't be needed in that case since this is something that can be ascertained by the compiler without parameters. The return type of a function is the same no matter how many overloads are provided for it.
So my first question is: have I misunderstood the necessity for this? In other words, is there an actual reason why I need to provide the parameters?
Second (and this is the real question), is there a way to do this that doesn't require me to provide these artificial parameters?
(1) Yes, I'm aware I can do something like using ShortType = std::map<std::string, std::tuple<int, SomeStructure>>;
but it's not always my code.
Your question is based on the false premise that all overloads would have the same return type. This is not correct. I suppose you confuse this with: You cannot overload a function based on the return type alone.
You cannot do this:
int foo();
float foo(); // error: cannot overload based on return type alone
But you can do this:
int bar(int);
float bar(float);
Consequently, you need the types of the parameters to select an overload. You do not need values:
#include <utility>
int a(const char *, int, float);
int main() {
using t1 = decltype(a("", 7, 4.2)); // okay
using t2 = decltype(a(std::declval<const char*>(),
std::declval<int>(),
std::declval<float>())); // okay !
}
std::declval
can be used in unevaluated context (like eg decltype
) to get a reference. Striclty speaking it isnt needed here, and I could have used also float{}
or int{}
. However, std::declval
is more generic and also works with types that have no default constructor.