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).
if constexpr (sizeof...(Ts)>0)
inside the lambda?)?Proposing an answer from the comments.
From fold expression cppreference:
Explanation ...
When a unary fold is used with a pack expansion of length zero, only the following operators are allowed:
- Logical AND (&&). The value for the empty pack is true
- Logical OR (||). The value for the empty pack is false
- The comma operator (,). The value for the empty pack is void()
emphasis mine.
Thus in ((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
, if the tuple is empty, the expression becomes void();
, resulting to n
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:
#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 << '[';
if constexpr (sizeof...(Ts)) {
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';
}
The if constexpr
is more verbose but also more explicit with respect to when n
is actually unused.
Strangely enough, I couldn't find a way to make gcc and clang issue a similar warning.