Is `auto` specifier slower in compilation time? - c++

Since C++11 we can use auto a = 1+2 instead of int a = 1+2 and the compiler deduces the type of a by itself. How does it work? Is it slower during compile time (more operations) than declaring the type myself?

auto is asking the C++11 compiler to make some limited kind of type inference (look into Ocaml if you want some more sexy type inference language). But the overhead is compile-time only.
If you replace auto a=1+2; with int a=1+2; (both have the same meaning, see answer by simplicis) and if you ask your compiler to optimize (and probably even without asking for optimizations) you'll probably get the same machine code. See also this.
If using GCC try to compile a small C++11 foo.cc file with g++ -Wall -fverbose-asm -O -S foo.cc and look (with an editor) into the generated foo.s assembler file. You'll see no difference in the generated code (but the assembler file might perhaps change slightly, e.g. because of metadata like debug information etc.)
If you are concerned about slower compile-time I guess that using auto is not a decisive factor (probably, overloading could be more costly in compilation time). C++11 is nearly designed to practically require a lot of optimizations (in particular sophisticated inlining and constant folding and dead code elimination), and its "parsing" (notably header inclusion and template expansion) is costly.
Precompiling headers and parallel builds with make -j (and perhaps ccache or distcc) might help in improving the overall compilation time, much more than avoiding auto.
And if you wanted to systematically avoid auto (in particular in range-for loops like std::map<std::string,int> dict; for (auto it: dict) {...}) you'll end up typing much more source code (whose parsing and checking takes significant time) with more risks of error. As explained here, you might guess slightly wrongly the type, and expliciting it (slightly wrongly) might slow down the execution of your code because of additional conversions.
If using GCC you might pass the -ftime-report to g++ and get time measurements about various GCC passes and phases.

The compiler knows the type an expression (like 1 + 2) evaluates to. That's just the way the language works -- both operands are of type int so the result is int as well. With auto a, you are just telling the compiler to "use the type of the initializing expression".
The compiler does not have to do any additional work or deducing here. The auto keyword is merely relieving you from figuring out the expression and writing the correct type. (Which you might get wrong, with probably unintended side-effects -- see this question (and the top answer) for an example how auto can avoid unintended run-time conversions and copying.
The auto keyword really comes into its own with iterators:
std::vector< std::string >::const_iterator it = foo.cbegin();
versus
auto it = foo.cbegin();

How does it work:
From the ISO/IEC:
...The auto specifier is a placeholder for a type to be deduced (7.1.6.4). The other simple-type-specifiers specify
either a previously-declared user-defined type or one of the fundamental types...
7.1.6.4 auto specifier
The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer
or that a function declarator shall include a trailing-return-type.
The auto type-specifier may appear with a function declarator with a trailing-return-type in any
context where such a declarator is valid.
Otherwise, the type of the variable is deduced from its initializer. The name of the variable being declared
shall not appear in the initializer expression. This use of auto is allowed when declaring variables in a
block, in namespace scope, and in a for-init-statement; 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 initdeclarators, each of which shall have a non-empty initializer...
Example:
auto x = 5; // OK: x has type int
const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int
static auto y = 0.0; // OK: y has type double
auto int r; // error: auto is not a storage-class-specifier
Is it faster:
The simple answer is Yes, by using it a lot of type conversions could be omitted, however, if not used properly it could become great source of errors.
In one of the interviews from Bjarne Stroustrup, he said that auto keyword has resulted in win-win situation for coders and compiler implementers.

Related

Could a compiler optimisaton give an lvalue rather than rvalue?

The following code:
int x = 0;
x+0 = 10;
unsurprisingly produces the compiler error
lvalue required as left operand of assignment
However, is it guaranteed that all standards-conforming compilers will produce a similar error, or could a compiler legitimately treat line 2 as
x = 10;
which then would compile?
Yes, it is guaranteed you get an error (or more precisely, some diagnostic). Compiler optimization never makes ill-formed code well formed.
Yes, compilers must reject this.
A good description of value categories can be found here:
https://medium.com/#barryrevzin/value-categories-in-c-17-f56ae54bccbe
One of the takeaways is, the value category of an expression can be determined by looking at the type decltype ((expr)).
Compiler optimations do not change the types of expressions, and they generally happen after name resolution, determination of types, overload resolution etc.
Gcc is known to perform some constant folding in the front end but i would be shocked if any version of gcc compiles your example.

Recursive descent parser, initialization of variable with itself, dilemma

I want to know whether conforming C++ compiler is required to support the following code:
int a(a); // no other a is visible, we mean initialization of a with itself
Visual Studio 2013 does not support it (undeclared identifier), however some other compilers compile it.
And here is our dilemma: for possible expression check we need to dispose information about a (including its type) since it can be part of expression, however there is another possibility that it is function, in this case we are only constructing type expression (and symbol a is probably not in the symbol table yet).
I think that recursive descent parser is more likely to run in this dilemma, since it is very structural in nature and supporting this specific case will be like a special 'crutch' (type expression is being constructed when we encounter a inside () and we are at some level of recursion). So I assume that visual studio uses recursive descent strategy.
So with all this in mind, whether it is worth compiler writer's effort and whether it is justified to support such code (especially when using recursive descent)?
[basic.scope.pdecl]
The point of declaration for a name is immediately after its complete
declarator (Clause 8) and before its initializer (if any), except as
noted below. [ Example:
unsigned char x = 12;
{ unsigned char x = x; }
Here the second x is initialized with its own (indeterminate) value. —end example]
In int a(a);, the declarator ends at the opening brace of the initializer, so yes, compilers are required to allow this (GCC helpfully gives an -Wuninitialized warning if it's an automatic variable).

Selectively suppress "unused variable" warnings for unused lambdas

Is there any way to suppress "unused variable" warnings for a specific file, namespace, or specific variable?
I ask because I have a namespace containing a big list of lambda functions. Some are not used now, but might be used in time. If these were regular free functions, I would not be warned if some were unused. However, because they are lambdas, I end up with a stack of compiler warnings.
I do not want to use a compiler flag to remove all of this type of warning, as normally, it is very useful to have the compiler catch unused variables. However, a stack of warnings about unused utility functions adds noise to otherwise useful information.
There are two approaches that come to mind. First of all, most build environments enable per-source compiler flags, so you should be able to turn off that warning just for the single file where all those lambdas are defined.
Then there is a general approach to silence such warnings for single variables: use it, but not really do anything with it. On some compilers this can be achieved with a simple cast to void:
auto x = /* ... */;
(void) x;
But more effective is defining a simple function that makes it look (for the compiler) as if the variable was used:
template <class T>
void ignore_unused(T&) {}
//later...
auto x = /* ... */;
ignore_unused(x);
Note the parameter has no name, so the compiler will not complain about that one to be unused.
The idea is pretty common: do something with the variable that effectively makes no operation but silences the static analyzer that emits the "unused variable" warning.
Boost has a similar function, boost::ignore_unused_variable_warning()
For more information, see Herb Sutter's blog.
In C++ you can static_cast anything to void.
What is the use of such a cast if it does not produce any side effects or a value one might ask?
Precisely to tell the compiler that an object is "used" in a portable way.
So,
auto x = /*...*/;
static_cast<void>(x);
Lambdas are just syntactic sugar for functors. Functors are a type of object (one that has operator() overloaded). So the compiler will warn if that variable (object) goes unused.
I recommend the block-comment method for hushing the compiler ;). Other than that, there's not much you can do to selectively and cleanly silence the compiler in the general case.
Note that if you have a more specific case, such as passing arguments in a function, you can make the argument nameless if you do not use it. Another thing you could do is put a (void)var reference somewhere in your code (although this is cheating; now you've referenced it!). Lastly, if your compiler supports it (the almighty GCC does), you might try using the __attribute__((unused)) preprocessor directive (use [[gnu::unused]] for Clang).
Depending on your situation, these suggestions may or may not help.
How about hiding the lambdas inside of generators. That way they don't even get created unless they are used. So instead of:
auto add_one= [](int x){ return x + 1 } ;
Use:
std::function<int(int)> gen_addone(void)
{
static auto l_= [](int x){ return x + 1 ; } ;
return l_ ;
}
Sorry, you'll have to wait till c++1y for automatic return type deduction.

implicit constexpr?

Can C++11 compilers (and do they) notice that a function is a constexpr and treat them as such even if they are not declared to be constexpr?
I was demonstrating the use of constexpr to someone using the example straight from the Wikipedia:
int get_five() {return 5;}
int some_value[get_five() + 7]; // Create an array of 12 integers. Ill-formed C++
To my surprise the compiler was OK with it. So, I further changed get_five( ) to take a few int parameters, multiply them and return the result while still not being explicitly declared to be constexpr. The compiler was OK with that as well. It seems that if the compiler can do this there isn't much point to having the restrictions that are required in order to explicitly declare something constexpr.
On a properly-functioning C++11 compiler, your code would be rejected.
Based on its being accepted, you're almost certainly using gcc (or something that closely emulates its bugs). gcc [depending somewhat on flags] can accept array sizes that aren't constant by any measure (e.g., depend on run-time input from the user) because they support an analog of C99 variable-length arrays in C++.
GCC, as of GCC 12, supports the -fimplicit-constexpr command-line toggle which enables exactly that, for methods marked as inline.
Changelog: https://gcc.gnu.org/gcc-12/changes.html
Patch with some rationale and discussion: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=87c2080b
A compiler can detect whether or not a function could have been declared with constexpr even when they haven't, for optimization purposes (i.e. computing the result of a function at compile-time). Compilers did that prior to C++11.
But for use in places that requires constant expressions, such as template parameters of integral type, it is against the standard to allow calls to functions that are not declared with the constexpr keyword.

Testing endianess at compile-time: is this constexpr function correct according to the standard?

After some search for a way to check endianess at compile-time I've come up with the following solution:
static const int a{1};
constexpr bool is_big_endian()
{
return *((char*)&(a)) == 1;
}
GCC accepts this code only in some contexts where constexpr is required:
int b[is_big_endian() ? 12 : 25]; //works
std::array<int, testendian() ? 12 : 25> c; //fails
For the second case, GCC says error: accessing value of ‘a’ through a ‘char’ glvalue in a constant expression. I couldn't find anything in the standard that forbids such thing. Maybe someone could clarify in which case GCC is correct?
This is what I get from Clang 3.1 ToT:
error: constexpr function never produces a constant expression
§5.19 [expr.const]
p1 Certain contexts require expressions that satisfy additional requirements as detailed in this sub-clause; other contexts have different semantics depending on whether or not an expression satisfies these requirements. Expressions that satisfy these requirements are called constant expressions.
p2 A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression:
[...]
a reinterpret_cast (5.2.10);
So, (char*)&(a) evaluates to a reinterpret_cast, as such the function is never a valid constexpr function.
You should look into Boost.Detail.Endian
It is a mapping of several architectures to their endianness (through the macros BOOST_BIG_ENDIAN, BOOST_LITTLE_ENDIAN, and BOOST_PDP_ENDIAN). As far as I know, there is no actual way to determine the endianness at compile time, other than a list like this.
For an example implementation that uses Boost.Detail.Endian, you can see the library I'm hoping to get reviewed for submission to Boost: https://bitbucket.org/davidstone/endian/ (the relevant file is byte_order.hpp, but unsigned.hpp is necessary as well if you want to just use my implementation).
If N3620 - Network Byte Order Conversion is implemented, you'll be able to use the constexpr ntoh to check for endianness, but remember there are rare architectures like middle-endian and you'll never be able to support all of them.