Reputation: 2038
Suppose we have this piece of code shown as below, the question is that why the cv qualifier (const) for "c" is not kept which the behavior is distinct from "v"?
int main(int argc, char **argv) {
int x{};
int y{};
const auto [v] = std::tuple<int>(x);
const auto [c] = std::tuple<int&&>(std::move(y));
decltype(v) vv = 10; // vv -> const int;
decltype(c) cc = 100; // cc -> int&&;
return 0;
}
Also, can I mimic the same type deduction process with template argument deduction somehow like below?
template<class T>
void foo(T t) { // here should be T rather than universal reference;
// mimic the same behavior as above somehow ...
}
Doubt 2:
For the code as below, it seems the "auto" inference for "Structured Binding" does not align the same rule as the normal usage of "auto"?
What I expect is that for the first "auto", the decltype(v)
should be the type of const int rather than int& like the second one since I do not specify a "&" beside "auto. So, any special rules for "Structured Binding" with "auto"?
int main(int argc, char **argv) {
int x{};
const auto [v] = std::tuple<int&>(x); // v -> int&;
static_assert(std::is_same_v<decltype(v), int&>);
int& rx = x;
const auto c = rx; // c -> const int;
static_assert(std::is_same_v<decltype(c), const int>);
return 0;
}
Upvotes: 2
Views: 307
Reputation: 7393
Given
const auto [v] = std::tuple<T>(x);
The type decltype(v)
is T const
, i.e. const
-qualified T
. If T
is int
, then decltype(v)
is int const
(which also may be written const int
). If T
is int&&
, then decltype(v)
is int&& const
which is int&&
(not const int&&
which is a reference to const int
). The type int&& const
is the same as int&&
because references are always effectively const
. The objects they refer to may be mutable, but references themselves in C++ are immutable.
With template type deduction without universal references, you cannot mimic this type transformation (add const
to T
) as far as I can tell. But there is a type transformation trait std::add_const_t<T>
.
Update for Doubt 2
The structured binding
const auto [v] = std::tuple<int&>(x); // v -> int&;
is not analogous to
int& rx = x;
const auto c = rx; // c -> const int;
It is instead analogous to
const auto e = std::tuple<int&>(x);
auto&& v = std::get<0>(std::move(e));
The const qualification applies to the tuple, not to the binding of v. The reference qualifier or lack of it applies to the tuple. The binding of v is always reference-like.
The oddness is actually in the other case:
const auto [v] = std::tuple<int>(x);
Still v is reference-like, but decltype(v)
is int
. The difference is that bindings in structured bindings are aliases, not references. They are different names for the things referred to, but don't themselves have reference types.
So:
const auto [v] = std::tuple<T>(x);
is most analagous to:
const auto e = std::tuple<T>(x);
auto&& r = std::get<0>(std::move(e));
(introduce v as a name for that which r refers to)
where that third line is not something we have the ability to write.
Upvotes: 3
Reputation: 132
As Jeff Garret mentioned, const
will apply to the entire auto
type deduced. If the type is int&
, for example, then const auto
will be the same as auto const
, which is the same as int& const
. The reference is const
, not the data.
Now, what can you do about this? You don't have to stop using auto
. You can simply specify const auto&
. auto
will deduce to int
, and the whole type will be const int&
(equivalently int const&
). This is how you get your data to be const.
Upvotes: 0