structured binding with [[maybe_unused]]
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.
structured bindings and range-based-for; supress unused warning in gcc
The relevant GCC pragmas are documented on this page.
#include <map>
std::map<int, int> my_map;
void do_something(int);
void loop()
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
for (auto & [unused, val]: my_map)
#pragma GCC diagnostic pop
do_something(val);
}
This is the smallest scope of the disabled warning that I could have, and still have the warning suppressed with -Wall -Wextra -Werror
.
[[maybe_unused]] with structured_binding?
As suggested by comments, -Wunused-variable
only appears in gcc7
[[maybe_unused]]
is not needed for newer gcc
std::ignore with structured bindings?
The structured bindings proposal contains a dedicated section answering your question (P0144R2):
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 astd::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.
However, note that the working draft of the Standard is currently being revised by the relevant National Bodies (NB), and there is a NB comment requesting this feature (P0488R0, US100):
Decomposition declarations should provide syntax to discard some of the returned values, just as
std::tie
usesstd::ignore
.
Structured binding violations
So they both still violate the rule that that structured bindings are never names of variables, making them never capturable?
No, it is actually clang that is violating the standard, at least for the compiler flags provided.
In C++20, the restriction of not directly supporting captures of structured binding aliases has been lifted, allowing them to be directly used without falling back to constructs using init-captures:
Change [expr.prim.lambda.capture]p8 (7.5.5.2) as follows:
If a lambda-expression explicitly captures an entity that is not odr-usable
or captures a structured binding (explicitly or implicitly)
, the program is ill-formed.
cv-qualifier propagation in structured binding
decltype
has a special rule when the member of a class is named directly as an unparenthesized member access expression. Instead of producing the result it would usually if the expression was treated as an expression, it will result in the declared type of the member.
So decltype(rf.x)
gives int
, because x
is declared as int
. You can force decltype
to behave as it would for other expressions by putting extra parentheses (decltype((rf.x))
), in which case it will give const int&
since it is an lvalue expression and an access through a const
reference.
Similarly there are special rules for decltype
if a structured binding is named directly (without parentheses), which is why you don't get const int&
for decltype(x)
.
However the rules for structured bindings take the type from the member access expression as an expression if the member is not a reference type, which is why const
is propagated. At least that is the case since the post-C++20 resolution of CWG issue 2312 which intends to make the const
propagation work correctly with mutable
members.
Before the resolution the type of the structured binding was actually specified to just be the declared type of the member with the cv-qualifiers of the structured binding declaration added, as you are quoting in your question.
I might be missing some detail on what declared type refers to exactly, but it seems to me that this didn't actually specify x
to have type const int&
in your first snippet (and decltype
hence also not const
), although that seems to be how all compilers always handled that case and is also the only behavior that makes sense. Maybe it was another defect, silently or unintentionally fixed by CWG 2312.
So, practically speaking, both rf.x
and x
in your example are const int
lvalue expressions when you use them as expressions. The only oddity here is in how decltype
behaves.
What part in cppreference tells me structured binding declarations only work with compile-time known objects?
The relevant part is std::tuple_size
, which yields a compile-time size. You can't implement that for std::vector
. It has a run-time variable std::vector::size
.
Related Topics
Get Function Names from Call Stack
How to Restart My Own Qt Application
C++ Abstract Class Without Pure Virtual Functions
If I Want to Specialise Just One Method in a Template, How to Do It
Enable a Single Warning in Visual Studio
Difference Between Initialization of Static Variables in C and C++
Member Access into Incomplete Type Error
Constant Variables Not Working in Header
Setjmp/Longjmp: Why Is This Throwing a Segfault
Call Destructor and Then Constructor (Resetting an Object)
Do These Members Have Unspecified Ordering
How to Compile for Windows Xp with Visual Studio 2012
Why Do Reference Type Members Cause Implicitly-Declared Copy Assignment Operator to Be Deleted
Why Is This Constexpr Static Member Function Not Seen as Constexpr When Called