在使用 MSVC 时,对空元组使用 std::apply 时出现未解释的警告。

huangapple go评论79阅读模式
英文:

unexplained warning when using std::apply on empty tuple with 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';
}

在线演示
使用/permissive-选项的MSVC,在最后一行输出以下警告:

(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 和 clang 不会发出任何警告。

由于我也使用了Werror//we,我想摆脱这个警告(如果可能的话,不使用#pragma)。

  1. 为什么 MSVC 的行为会这样?
  2. 我如何摆脱这个警告(在 lambda 内部添加 if constexpr (sizeof...(Ts)>0) 会有帮助吗?
英文:

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 &lt;iostream&gt;
#include &lt;tuple&gt;
#include &lt;utility&gt;

template &lt;typename... Ts&gt;
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, std::tuple&lt;Ts...&gt; const&amp; theTuple) {
    std::apply(
        [&amp;os](Ts const&amp;... tupleArgs) {
            os &lt;&lt; &#39;[&#39;;
            std::size_t n{0};
            ((os &lt;&lt; tupleArgs &lt;&lt; (++n != sizeof...(Ts) ? &quot;, &quot; : &quot;&quot;)), ...);
            os &lt;&lt; &#39;]&#39;;
        },
        theTuple);
    return os;
}

int main() {
    // serialization example
    std::tuple myTuple{25, &quot;Hello&quot;, 9.31f, &#39;c&#39;};
    std::cout &lt;&lt; myTuple &lt;&lt; &#39;\n&#39;;
    std::cout &lt;&lt; std::tuple&lt;&gt;() &lt;&lt; &#39;\n&#39;;
}

Live<br>
MSVC, with /permissive-, outputs the following warning with the very last line:
> <source>(10): warning C4189: 'n': local variable is initialized but not referenced<br>
> <source>(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).

  1. Why does msvc behaves like that?
  2. How can I get rid of this warning (adding a if constexpr (sizeof...(Ts)&gt;0) inside the lambda?)?

答案1

得分: 1

fold expression cppreference中提出一个答案。

> 解释
...<br>
当一个一元折叠与长度为零的包扩展一起使用时,只允许以下操作符:
>
> 1) 逻辑与(&&)。空包的值为true
> 2) 逻辑或(||)。空包的值为false<br>
> 3) 逗号操作符(,)。空包的值为void()

重点在于。
因此,在 ((os &lt;&lt; tupleArgs &lt;&lt; (++n != sizeof...(Ts) ? &quot;, &quot; : &quot;&quot;)), ...); 中,如果元组为空,则表达式变为 void();,导致 n 未被使用,因此 msvc 正确地发出警告。

然后,可以通过简单的 [[maybe_unused]] std::size_t n{0}; 来消除此警告。

可以争论地,我们也可以这样写:

#include &lt;iostream&gt;
#include &lt;tuple&gt;
#include &lt;utility&gt;

template &lt;typename... Ts&gt;
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, std::tuple&lt;Ts...&gt; const&amp; theTuple) {
    std::apply(
        [&amp;os](Ts const&amp;... tupleArgs) {
            os &lt;&lt; &#39;[&#39;;
            if constexpr (sizeof...(Ts)) {
                std::size_t n{0};
                ((os &lt;&lt; tupleArgs &lt;&lt; (++n != sizeof...(Ts) ? &quot;, &quot; : &quot;&quot;)), ...);
            }
            os &lt;&lt; &#39;]&#39;;
        },
        theTuple);
    return os;
}

int main() {
    // serialization example
    std::tuple myTuple{25, &quot;Hello&quot;, 9.31f, &#39;c&#39;};
    std::cout &lt;&lt; myTuple &lt;&lt; &#39;\n&#39;;
    std::cout &lt;&lt; std::tuple&lt;&gt;() &lt;&lt; &#39;\n&#39;;
}

Live

if constexpr 更冗长,但在 n 实际未使用时更明确。<br>
奇怪的是,我找不到一种方法来让 gcc 和 clang 发出类似的警告。

英文:

Proposing an answer from the comments.

From fold expression cppreference:
> Explanation
...<br>
When a unary fold is used with a pack expansion of length zero, only the following operators are allowed:
>
> 1) Logical AND (&&). The value for the empty pack is true
> 2) Logical OR (||). The value for the empty pack is false<br>
> 3) The comma operator (,). The value for the empty pack is void()

emphasis mine.
Thus in ((os &lt;&lt; tupleArgs &lt;&lt; (++n != sizeof...(Ts) ? &quot;, &quot; : &quot;&quot;)), ...);, 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 &lt;iostream&gt;
#include &lt;tuple&gt;
#include &lt;utility&gt;

template &lt;typename... Ts&gt;
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, std::tuple&lt;Ts...&gt; const&amp; theTuple) {
    std::apply(
        [&amp;os](Ts const&amp;... tupleArgs) {
            os &lt;&lt; &#39;[&#39;;
            if constexpr (sizeof...(Ts)) {
                std::size_t n{0};
                ((os &lt;&lt; tupleArgs &lt;&lt; (++n != sizeof...(Ts) ? &quot;, &quot; : &quot;&quot;)), ...);
            }
            os &lt;&lt; &#39;]&#39;;
        },
        theTuple);
    return os;
}

int main() {
    // serialization example
    std::tuple myTuple{25, &quot;Hello&quot;, 9.31f, &#39;c&#39;};
    std::cout &lt;&lt; myTuple &lt;&lt; &#39;\n&#39;;
    std::cout &lt;&lt; std::tuple&lt;&gt;() &lt;&lt; &#39;\n&#39;;
}

Live

The if constexpr is more verbose but also more explicit with respect to when n is actually unused.<br>
Strangely enough, I couldn't find a way to make gcc and clang issue a similar warning.

huangapple
  • 本文由 发表于 2023年6月19日 20:33:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76506670.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定