The following code compiles successfully both with clang++ 3.8.0 and g++ 7.2.0 (the compilation flags are -std=c++14 -O0 -Wall -Wextra -Werror -pedantic-errors
):
#include <iostream>
int foo_int(int)
{
std::cout << "int foo(int)" << std::endl;
return 0;
}
void foo_void(int)
{
std::cout << "void foo(int)" << std::endl;
}
auto foo_auto_int(int)
{
std::cout << "auto foo(int), auto == int" << std::endl;
return 0;
}
auto foo_auto_void(int)
{
std::cout << "auto foo(int), auto == void" << std::endl;
return void();
}
int main()
{
auto (*fi)(int) = foo_int;
auto (*fv)(int) = foo_void;
auto (*fai)(int) = foo_auto_int;
auto (*fav)(int) = foo_auto_void;
(void)fi(0);
fv(0);
(void)fai(0);
fav(0);
}
Is it a valid C++ code?
Note that the decltype(auto)
is rejected both by clang++ and g++ in the same situation.
In the case of functions, the auto keyword before the function name or the auto return type signifies that the return type of that function will be evaluated from the return type expressions at runtime. From C++ 11, this keyword was introduced; before that, the programmer needed to assign each variable’s data type explicitly at compile time.
Note: The variable declared with auto keyword should be initialized at the time of its declaration only or else there will be a compile-time error. Note: We have used typeid for getting the type of the variables. Typeid is an operator which is used where the dynamic type of an object needs to be known.
The auto keyword cannot be combined with any other type-specifier. A symbol that is declared with the auto keyword must have an initializer. You incorrectly used the auto keyword to declare a type. For example, you declared a method return type or an array. A parameter or template argument cannot be declared with the auto keyword.
Using auto to deduce the return type of a function in C++11 is way too verbose. First, you have to use the so-called trailing return type and second, you have to specify the return type in a decltype expression. You have to read the expression auto sum (T t, T2 t2) -> decltype (t + t2) in the following way.
The compilers are behaving correctly.
From [dcl.spec.auto]
The
auto
anddecltype(auto)
type-specifiers are used to designate a placeholder type that will be replaced later by deduction from an initializer.[...]
auto
ordecltype(auto)
shall appear as one of the decl-specifiers in the decl-specifier-seq and the decl-specifier-seq shall be followed by one or more declarators, each of which shall be followed by a non-empty initializer.
Which is saying auto
and decltype(auto)
can only be written with the specifiers you write in the front of a declaration (static
, virtual
etc), with their types deduced from the immediately following declarators with initializers.
auto
The declarator in the case of auto (*fi)(int) = foo_int;
is (*fi)(int)
which is of the form
( ptr-operator declarator-id ) ( parameter-declaration-clause )
Hence auto (*fi)(int) = foo_int;
is valid, provided the deduction succeeds, which it does. Likewise for the other few.
decltype(auto)
From [dcl.spec.auto.deduct], given a type T
containing a placeholder type
If the placeholder is the
decltype(auto)
type-specifier,T
shall be the placeholder alone.
Which means adding anything else is illegal
int i;
decltype(auto)* p = &i; // error, declared type is not plain decltype(auto)
Hence decltype(auto) (*fi)(int) = foo_int;
is illegal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With