I recall someone once telling me,
"there is no need for auto inside range-based for loops. It would
not be ambiguous in the language if we were to remove it."
Is that a true statement?
Is the folowing code valid C++ syntax?
for (elem : range){...}
I had assumed this was already valid syntax, but when I went to compile with
clang++ --std=c++1z, I was shown the following error:
range-based for loop requires type for loop variable
for (elem: range){
The compiler still recognizes this as a range-based for loop, so why can't it also derive the type?
The:
for (elem : range){...}
syntax is not currently valid but there was a proposal to make this valid syntax and the syntax is supported in gcc 5.2 (see it live):
#include <vector>
int main()
{
std::vector<int> v ;
for( elem : v )
{
}
}
and if we try this in C++14 mode it says:
warning: range-based for loop without a type-specifier only available
with -std=c++1z or -std=gnu++1z
So this would clearly work and has been implemented in gcc. It looks like this feature was removed in gcc 6.0.
As far as I can tell this was implemented in gcc with the expectation that proposal N3853: Range-Based For-Loops: The Next Generation would be accepted but it was rejected and the updated version N3994 says:
This updates N3853 (see [1]) which proposed the syntax "for (elem :
range)", by adding support for attributes and answering additional
questions. Please see the original proposal for the rationale behind
this feature, which is not repeated here.
We can see it was rejected from the EWG issue 81 and we can also see this from the Urbana meeting minutes. Although there are many issues with the proposal I believe STL made a convincing set of arguments in the Question and Answers section of the proposal and I was disappointed that the proposal was rejected.
The syntax requires a type for a range-for statement, even if it's auto. for (elem : range) {...} is a syntax error, so technically, yes, it's true, the language could state that this is equivalent to for (auto elem : range) {...}.
There are at least two major problems with that, though:
The first is that for (T elem : range) doesn't require T to use auto. If the compiler sees for (elem, it wouldn't yet have any way of knowing whether elem is some typedef from an outer scope, or a newly declared variable. It's not ambiguous, but it's a bit complicated for compilers to handle correctly.
The second is that you then get the question of what the default should be. Legitimate arguments could be made for auto. Legitimate arguments could be made for auto &. Legitimate arguments could be made for const auto &. The current approach just lets the programmer choose. Legitimate arguments could probably (I'm not entirely sure) also be made for some of those with auto replaced by decltype(auto).
This is really a question for ELL...
The sentence is written in the subjunctive case, meaning that it is talking about a purely hypothetical situation, not the actual language rules. Subjunctive is used for counterfactual situations.
Related
Functional languages with pattern matching (sometimes?) have the possibility to ignore some bound values, but with C++17 structured bindings there seem to be no way to do that (std::ignore with structured bindings?). The advice is to use a dummy name, but then we'll get warnings about unused variables.
With the latest heads of both clang and gcc, this does the expected thing, which is nice and useful,
[[maybe_unused]] auto x =4 ; // fine, no warning
[[maybe_unused]] auto [a,dummyb,dummyc] = std::tuple<int,int,float>(1,1,1.0f);
but I would also have hoped this would work:
auto [g,[[maybe_unused]]dummyh,[[maybe_unused]]dymmyi] =
std::tuple<int,int,float>(1,1,1.0f);
is there a specific reason attributes can not be used here? (in the standard as well as technically). Neither gcc or clang accepts this.
Edit, collecting the support status: (thanks to godbolt/compiler explorer). It works as expected in (could be earlier also):
gcc 8.0 trunk (g++ 8.0.0 20171015 experimental)
clang 4.0.0
icc 18 (not tested, according to specs)
msvc 19.22 (probably earlier) (Fixed, according to bug report)
Try it out in godbolt at https://gcc.godbolt.org/z/H2duYd
In the structure bindings paper:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0144r2.pdf
they discuss their reasoning:
3.8 Should there be a way to explicitly ignore components?
The motivation would be to silence compiler warnings about unused names.
We think the answer should be “not yet.” This is not motivated by use
cases (silencing compiler warnings is a motivation, but it is not a
use case per se), and is best left until we can revisit this in the
context of a more general pattern matching proposal where this should
fall out as a special case.
Symmetry with std::tie would suggest using
something like a std::ignore:
tuple<T1,T2,T3> f();
auto [x, std::ignore, z] = f(); // NOT proposed: ignore second element
However, this feels awkward.
Anticipating pattern matching in the language
could suggest a wildcard like _ or *, but since we do not yet have
pattern matching it is premature to pick a syntax that we know will be
compatible. This is a pure extension that can wait to be considered
with pattern matching.
Although this does not explicitly address [[maybe_unused]], I assume the reasoning might be the same. Stopping compiler warnings is not a use-case.
As a resolution to CWG 2360, the working draft of the standard gained the following wording ([dcl.attr.unused]):
The attribute may be applied to the declaration of a class, a typedef-name, a variable (including a structured binding declaration), a non-static data member, a function, an enumeration, or an enumerator.
For an entity marked maybe_unused, implementations should not emit a warning that the entity or its structured bindings (if any) are used or unused. For a structured binding declaration not marked maybe_unused, implementations should not emit such a warning unless all of its structured bindings are unused.
Structured binding declarations were previously not explicitly mentioned.
This is inspired by this post where
non-trivial designated initializers are not supported.
I've already read this post and some answers claim this feature is already supported.
However, using C++17 and this code:
struct s {
int a[2];
s (int b): a{[1]=b} {} // error
};
s foo(1);
I still get the error:
sorry, unimplemented: non-trivial designated
initializers not supported
s (int b): a{[1]=b} {}
I was thinking this feature is really helpful.
So my questions:
Is there a plan to support this for future C++ versions (post C++17)?
If not, what is the biggest hindrance why it's not going to be supported
If yes, what is the problem with the current C++ version why it takes too long for this to be supported
COMPILER
GNU C++17 - Check wandbox
The proposal adopted to add designated initializers to C++20 (p0329r0) is limited, intentionally (Note that as an official language feature, it's specifically a C++20 feature - but gcc and clang have supported essentially this feature for a long time already):
C++ is a more complex language than C, and we have more things to worry about. So the rules we get are that you cannot mix designators and values, the designators appear in declaration order, are unique, and are neither nested nor array indices. This is already a very useful language feature, as-is.
If not, what is the biggest hindrance why it's not going to be supported
Motivation, probably. Do we really need that syntax? Is it a problem that needs solving? On the downside, there may be parsing ambiguities - you might be able to construct array index initializers that look a lot like lambdas. But if you think it's sufficiently worthwhile, you could write a proposal.
Functional languages with pattern matching (sometimes?) have the possibility to ignore some bound values, but with C++17 structured bindings there seem to be no way to do that (std::ignore with structured bindings?). The advice is to use a dummy name, but then we'll get warnings about unused variables.
With the latest heads of both clang and gcc, this does the expected thing, which is nice and useful,
[[maybe_unused]] auto x =4 ; // fine, no warning
[[maybe_unused]] auto [a,dummyb,dummyc] = std::tuple<int,int,float>(1,1,1.0f);
but I would also have hoped this would work:
auto [g,[[maybe_unused]]dummyh,[[maybe_unused]]dymmyi] =
std::tuple<int,int,float>(1,1,1.0f);
is there a specific reason attributes can not be used here? (in the standard as well as technically). Neither gcc or clang accepts this.
Edit, collecting the support status: (thanks to godbolt/compiler explorer). It works as expected in (could be earlier also):
gcc 8.0 trunk (g++ 8.0.0 20171015 experimental)
clang 4.0.0
icc 18 (not tested, according to specs)
msvc 19.22 (probably earlier) (Fixed, according to bug report)
Try it out in godbolt at https://gcc.godbolt.org/z/H2duYd
In the structure bindings paper:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0144r2.pdf
they discuss their reasoning:
3.8 Should there be a way to explicitly ignore components?
The motivation would be to silence compiler warnings about unused names.
We think the answer should be “not yet.” This is not motivated by use
cases (silencing compiler warnings is a motivation, but it is not a
use case per se), and is best left until we can revisit this in the
context of a more general pattern matching proposal where this should
fall out as a special case.
Symmetry with std::tie would suggest using
something like a std::ignore:
tuple<T1,T2,T3> f();
auto [x, std::ignore, z] = f(); // NOT proposed: ignore second element
However, this feels awkward.
Anticipating pattern matching in the language
could suggest a wildcard like _ or *, but since we do not yet have
pattern matching it is premature to pick a syntax that we know will be
compatible. This is a pure extension that can wait to be considered
with pattern matching.
Although this does not explicitly address [[maybe_unused]], I assume the reasoning might be the same. Stopping compiler warnings is not a use-case.
As a resolution to CWG 2360, the working draft of the standard gained the following wording ([dcl.attr.unused]):
The attribute may be applied to the declaration of a class, a typedef-name, a variable (including a structured binding declaration), a non-static data member, a function, an enumeration, or an enumerator.
For an entity marked maybe_unused, implementations should not emit a warning that the entity or its structured bindings (if any) are used or unused. For a structured binding declaration not marked maybe_unused, implementations should not emit such a warning unless all of its structured bindings are unused.
Structured binding declarations were previously not explicitly mentioned.
quite some time ago i noticed that in Visual C++ 10 ADL fails when at least one of the arguments is a lambda.
std::vector<float> vec;
for_each(begin(vec), end(vec), [](float) {});
The above fails to compile on VC++10 and 11 (beta) (begin and end are found via ADL). When i convert the lambda function into a regular free function things work just as expected.
I've asked on Herb Sutters blog once and also read some posts on msdn connect and the usual answers were: this is a bug, we havent implemented the latest standard of the lambdas yet which - at that time - was quite understandable. Things haven't been in a baked form yet. On MS connect there have also been disturbing comments that this will not be resolved for the next release i.e. vc 11.
My question is, is this code expected to work under the C++11 standard? I cant quite figure that out. Do i really have to prefix my for_each and other algorithms with std:: when I'm using lambdas?
I somehow suspect that this behavior will not change after vc++11 release.
The standard doesn't guarantee what you'd want it to..
With the below in mind we can easily realize that there is nothing guaranteeing that ADL would work in cases similar to the example provided in your post.
std::begin (c)/std::end (c)
The functions are described in the standard as the below quotation:
template <class C> auto begin(C& c) -> decltype(c.begin());
template <class C> auto end(C& c) -> decltype(c.end());
Though the Container< ... >::iterator (which is the return-type of c.begin ()) is an implementation-defined type.
More about the matter can be read upon at 24.5.6 Range Access, and 23.3.6.1/2 class template vector (or any other template STL container).
[](){} - Lambda Expressions
A lambda is an implementation-defined type, there is nothing in the standard stating that the resulting object will be of a type which is under namespace std.
It can pretty much exists wherever it wants, as long as it confirms to the other rules set up by the standard.
Too Long; Didn't Read
The types of which std::begin/std::end/a lambda-expression yields are not guaranteed to be under namespace std, therefore ADL is not guaranteed to kick in.
That is perfectly valid code. Any bug-free compiler will be able to compile it. But since MSVC has bug and so is unable to search the function through ADL, then maybe you should not rely on ADL and instead qualify it with std:: helping the compiler to find the function.
While qualifying an enumeration value with the name of the enumeration is not valid C++03, it is valid C++11, from what I understand. Despite this, MSVC 10 generates warning C4482 for the following:
enum E { A, B };
int i = E::A; // warning C4482 (but valid C++11?)
Since much of our code uses C++11 features (especially lambdas), it seems safe to disable this warning. Am I right that the code is valid C++11?
Note: I did not write the code in question, and I would prefer to not go through and change every occurrence of this.
Edit: Added some relevant links.
MSDN page for the warning.
Another question about the warning. The question and answers all seem to reference C++03.
Since much of our code uses C++11 features (especially lambdas), it seems safe to disable this warning.
If you're already relying on C++11 features, then yes. C++11 does allow you to use regular enums scoped by the enumeration's name. Microsoft had this as an extension for some time, so they issued a warning about the non-standard behavior.
So you can disable it.
Note that older compilers like VC2010, instead of warning, did raise compile error C2653 (with message "... is not a class or namespace name").