необъяснимое предупреждение при использовании std::apply для пустого кортежа с msvc
У меня есть предупреждение о переменной, на которую нет ссылки, при использовании std::apply для пустого кортежа. Этот фрагмент, вдохновленный std::apply cppreference, показывает проблему:
#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';
}
Живой
MSVC, с/permissive-
, выводит следующее предупреждение в самой последней строке:
(10): предупреждение C4189: 'n': локальная переменная инициализируется, но на нее нет ссылки
(22): примечание: см. ссылку на создание экземпляра шаблона функции 'std::ostream &operator (std::ostream &,const std::tuple &) ' компилируется
gcc и clangs ничего не выдают.
Поскольку я также используюWerror
//we
Я хотел бы избавиться от этого предупреждения (по возможности, без использования прагмы).
- Почему msvc ведет себя так?
- Как мне избавиться от этого предупреждения (добавив
if constexpr (sizeof...(Ts)>0)
внутри лямбды?)?
1 ответ
Предлагаю ответ из комментариев.
Пояснение...
При использовании унарной складки с раскрытием пачки нулевой длины разрешены только следующие операторы:
- Логическое И (&&). Значение для пустой упаковки истинно.
- Логическое ИЛИ (||). Значение пустого пакета неверно.
- Оператор запятая (,). Значение пустого пакета — void().
акцент мой. Таким образом, в((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
, если кортеж пуст, выражение принимает видvoid();
, что приводит к тому, что он не используется, поэтому msvc имеет право выдать предупреждение.
Тогда это предупреждение можно заглушить простым[[maybe_unused]] std::size_t n{0};
.
Возможно, мы могли бы также написать:
#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
является более подробным, но также и более явным в отношении того, когдаn
фактически не используется.
Как ни странно, я не смог найти способ заставить gcc и clang выдавать подобное предупреждение.