I have a warning about unreferenced variable when using std::apply on an empty tuple. This snippet, inspired from std::apply cppreference shows the issue:
#include <iostream>
#include <tuple>
#include <utility>
template <typename... Ts>
std::ostream& operator<<(std::ostream& os, std::tuple<Ts...> const& theTuple) {
std::apply(
[&os](Ts const&... tupleArgs) {
os << '[';
std::size_t n{0};
((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
os << ']';
},
theTuple);
return os;
}
int main() {
// serialization example
std::tuple myTuple{25, "Hello", 9.31f, 'c'};
std::cout << myTuple << '\n';
std::cout << std::tuple<>() << '\n';
}
Live
MSVC, with /permissive-
, outputs the following warning with the very last line:
(10): warning C4189: 'n': local variable is initialized but not referenced
(22): note: see reference to function template instantiation 'std::ostream &operator (std::ostream &,const std::tuple &)' being compiled
gcc and clangs do not issue anything.
As I'm using also Werror
//we
I'd like to get rid of this warning (without using pragma, if possible).
- Why does msvc behaves like that?
- How can I get rid of this warning (adding a
if constexpr (sizeof...(Ts)>0)
inside the lambda?)?
Proposing an answer from the comments.
From fold expression cppreference:
emphasis mine. Thus in
((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
, if the tuple is empty, the expression becomesvoid();
, resulting ton
not being used, thus msvc is right to issue a warning.Then, this warning can be silenced by a mere
[[maybe_unused]] std::size_t n{0};
.Arguably we could also write:
Live
The
if constexpr
is more verbose but also more explicit with respect to whenn
is actually unused.Strangely enough, I couldn't find a way to make gcc and clang issue a similar warning.