Will Automatic Return Type Deduction Work for Main

Will automatic return type deduction work for main?

No, it won't be allowed. Paragraph 7.1.6.4/10 of the C++14 Standard Draft N3690 specifies:

If a function with a declared return type that uses a placeholder type has no return statements, the return
type is deduced as though from a return statement with no operand at the closing brace of the function
body. [...]

This means that omitting a return statement in main() would make its type void.

The special rule introduced by paragraph 3.6.1/5 about flowing off the end of main() specifies:

[...] If control reaches the end
of main without encountering a return statement, the effect is that of executing

return 0;

The wording says that the "effect" during the execution of the program is the same as though a return 0 was present, not that a return statement will be added to the program (which would affect type deduction according to the quoted paragraph).

EDIT:

There is a Defect Report for this (courtesy of Johannes Schaub):

Proposed resolution (November, 2013):

Change 3.6.1 [basic.start.main] paragraph 2 as follows:

An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a declared return type of type int, but otherwise its type is implementation-defined. All implementations An implementation shall allow both

  • a function of () returning int and
  • a function of (int, pointer to pointer to char) returning int

as the type...

Why does auto return type deduction work with not fully defined types?

Your guess is correct. A deduced return type is not actually deduced until the signature of the function is needed. This means that it will be deduced in the context of the call to getCallOperator, at which point Foo is fully defined.

This is specified in 7.1.6.4p12:

Return type deduction for a function template with a placeholder in its declared type occurs when the definition is instantiated even if the function body contains a return statement with a non-type-dependent operand.

When should I use C++14 automatic return type deduction?

C++11 raises similar questions: when to use return type deduction in lambdas, and when to use auto variables.

The traditional answer to the question in C and C++03 has been "across statement boundaries we make types explicit, within expressions they are usually implicit but we can make them explicit with casts". C++11 and C++1y introduce type deduction tools so that you can leave out the type in new places.

Sorry, but you're not going to solve this up front by making general rules. You need to look at particular code, and decide for yourself whether or not it aids readability to specify types all over the place: is it better for your code to say, "the type of this thing is X", or is it better for your code to say, "the type of this thing is irrelevant to understanding this part of the code: the compiler needs to know and we could probably work it out but we don't need to say it here"?

Since "readability" is not objectively defined[*], and furthermore it varies by reader, you have a responsibility as the author/editor of a piece of code that cannot be wholly satisfied by a style guide. Even to the extent that a style guide does specify norms, different people will prefer different norms and will tend to find anything unfamiliar to be "less readable". So the readability of a particular proposed style rule can often only be judged in the context of the other style rules in place.

All of your scenarios (even the first) will find use for somebody's coding style. Personally I find the second to be the most compelling use case, but even so I anticipate that it will depend on your documentation tools. It's not very helpful to see documented that the return type of a function template is auto, whereas seeing it documented as decltype(t+u) creates a published interface you can (hopefully) rely on.

[*] Occasionally someone tries to make some objective measurements. To the small extent that anyone ever comes up with any statistically significant and generally-applicable results, they are completely ignored by working programmers, in favour of the author's instincts of what is "readable".

Warning with automatic return type deduction: why do we need decltype when return defines the type anyway?

What am I doing wrong?

Nothing. GCC 4.8 implements auto-deduced return types, but as an enabled-by-default C++1y feature. Compiling with -std=c++1y will remove that warning.

[Answer converted from this comment.]

Why can the return type of main not be deduced?

Reading the C++17 draft §3.6.1/2:

... and it shall have a declared return type of type int, ...

So yes I would say it's forbidden to use deduction.


Almost the exact same wording in the last C++14 draft (same section as the C++17 draft):

It shall have a declared return type of type int, ...


Just a personal reflection on the possible reasoning behind this, after reading comments and other answers. The reasoning return-type deduction is not allowed is (I think) because then the return type isn't known by the compiler until it sees a return statement. It's also not uncommon that other types (that are implicitly convertible to int) might be returned which would make the deduced type wrong. Declaring the return type up-front (either by the normal old-fashioned way, or by using trailing return type) will set the type when the function is declared, and can be checked by the compiler then and there to be correct.

As for allowing type-aliases, they are just aliases of a type. So allowing e.g.

typedef int my_type;
my_type main() { ... }

is really no different from

int main() { ... }

Does auto return type deduction force multiple functions to have the same return type?

Based on the following, GCC has the right behaviour in this case, but only by coincidence (see below):

§7.1.6.4 [dcl.spec.auto]/8

If the init-declarator-list contains more than one init-declarator, they shall all form declarations of variables.

Why only by coincidence? The error message is a clue. Changing the functions to deduce the same return type causes GCC to compile the code. While it's correct in giving an error here, albeit a misleading one, it only does so when the deduced type is inconsistent. It should always give an error.

`auto` return type in context of class members

If you want to use return type deduction, you cannot separate the declaration and definition into different files (not unless everyone includes both). There's no workaround for this other than to use an actual type.

When C++ goes to compile code that calls func, it must be able to know, at that time, what it will return. Without having definition in that translation unit, the compiler cannot know what will be returned. And therefore, the compiler cannot compile that code. And C++'s compilation model does not allow it to use information from other translation units in this way.

The best you might be able to do is wait for modules, which may be able to get around this.

Don't think of return type deduction as a way to never have to write return types. It's a feature intended for circumstances where the return type is awkward to write, where the most reasonable way to write it is as a decltype(expr), and expr is the exact expression you're going to return. And those cases are typically in template code, which has to go into headers anyway. If the return type is simple and obvious to you, there's really little reason not to put it there. Don't use return type deduction by default.

Why is no deduction for template parameters only used as return type?

Generally it is not possible to deduce function based on its return type. But if you use automatic types conversion c++ feature then you could achieve what you need:

template <typename T>
T zero() { return 1; }

template <>
float zero<float>() { return 3.0f; }

struct Zero
{
template<typename T>
operator T()
{
return zero<T>();
}
};

int main()
{
int x = Zero();
float y = Zero();
return x + y;
}

First you create temporary object Zero(), and during assigment we use conversion operator to execute correct specialization of zero template function.

Wrong automatic return type deduction in Typescript

Solution

Thanks to @Etheryte I found a solution: there's a way to enforce type widening by using conditional types.

export type ValueType<T> = T extends string
? string
: T extends number
? number
: T extends boolean
? boolean
: T extends undefined
? undefined
: [T] extends [any]
? T
: object;

which can be used so (note the only change, for the return type):

    /**
* Returns the value stored at the given key, which can have the form `qualifier.subKey`.
*
* @param key The key to look up.
* @param defaultValue An optional value to be returned if the there's no value at the given key or the key doesn't
* exist at all.
*
* @returns If a return value is given the return type is the same as that of the default value. Otherwise it's
* either undefined or the same as the type found at the given key.
*/
public get<T>(key: string, defaultValue: T): ValueType<T>;
public get(key: string): any;
public get<T>(key: string, defaultValue?: T): T | undefined {
const { target, subKey } = this.objectForKey(key, false);
if (!target || !subKey) {
return defaultValue;
}

return target[subKey] as T ?? defaultValue;
}

This also works for enums, where the conditional type returns number or string, depending on the base type of the enum.



Previous Answer

This behavior is by design. Literal values that are assigned to constant targets keep their literal type. This follows the principle of always storing the most narrow type. In situations where values can be changed (e.g. by assigning a literal to a mutable variable) the Typescript transpiler widens the type to allow for other values than the initial literal. You can read a bit more about that in the article Literal Type Widening in TypeScript.

There's no way (I know of) to force type widening, so I see 3 possible ways here:

  1. Use a mutable target when you assign the result from the get call. This might be problematic, because linters will try to "optimize" the variable to become immutable, if there are no other assignments to it.

  2. Add an explicit type annotation to the target, like:

const removeIdleTime: number = settings.get("workers.removeIdleTime", 60);


  1. Specify the generic parameter explicitly:

const removeIdleTime = settings.get<number>("workers.removeIdleTime", 60);

or

const removeIdleTime = settings.get("workers.removeIdleTime", 60 as number);

All these ways are not really a solution to my question, though.

Deduced type with 'auto &&' as function return type

Pretty sure what you are looking for is decltype(auto). This will return by value if the expression in the return statement returns by value, and it will return by reference if the expression in the return statement returns by reference. That would give you

decltype(auto) f() const { 
return a.f();
}


Related Topics



Leave a reply



Submit