10

平均値を計算する次の関数があります。

template<typename... Ts>
auto mean_of(const Ts... values)
{
    return (... + values) / static_cast<double>(sizeof...(Ts));
}

VS 2017 15.6.0 Preview 3 では、次のコード

std::cout << mean_of(1, 3);

出力します2.5。MSVC は fold 式を1 + 3 / Nではなく として解釈しているよう(1 + 3) / Nです。折りたたみ式の周りに括弧を追加すると、結果は正しくなります。GCC では余分な括弧は必要ありません。

これは MSVC のバグですか、それとも余分な括弧が必要ですか?

4

2 に答える 2

10

これは MSVC のバグです。私はそれを次のように減らしました:

template<class... Ts>
constexpr auto f1(Ts const... vals) {
    return 0 * (vals + ...);
}

template<class... Ts>
constexpr auto f2(Ts const... vals) {
    return (vals + ...) * 0;
}

static_assert(f1(1,2,3) == 0);
static_assert(f1(1,2,3) != 0 * 1 + (2 + 3));
static_assert(f2(1,2,3) == 0);
static_assert(f2(1,2,3) != 1 + (2 + 3) * 0);

( GCCclangの両方で正常にコンパイルされますがstatic_assert、MSVC で4 つすべての s がトリガーされます) を内部でファイルしました。

20180205 更新: このバグは、Visual C++ の今後のリリースで修正されました。

于 2018-02-04T19:01:22.607 に答える
4

興味深い質問です。

私の最初の解釈を修正すると、g++ と clang++ が正しく、MSVC が間違っているように思えます。

これは、C++17 のドラフト n4659 (申し訳ありませんが、最終バージョンにはアクセスできません) で、除算演算子が "乗算式"に含まれる式規則 (A.4) が表示されるためだと思います。次のようにルール

乗法式/ pm式

"乗法式" は " pm-式" にもなり、"キャスト式" にもなり、"単項式" にもなり、"後置式" にもなり、"一次式" にもなります。 " これは " fold-expression "にすることができます

したがって、ルールは次のように見ることができます

折り式/ pm式

したがって、私が間違っていなければ、除算を適用する前に「fold-expression」を全体として評価する必要があります。

私の最初の解釈 (MSVC は正しい、g++ と clang++ は間違っている) は、17.5.3 の性急な講義に基づいていました。

fold-expressionのインスタンス化により、以下が生成されます。

(9.1) ((E1 op E2) op ···) op EN 単項左折畳

および 8.1.6

op折り畳み演算子である形式 (... op e)の式は、単項左折り畳みと呼ばれます。

だから私はそれを推測した

return (... + values) / static_cast<double>(sizeof...(Ts));

インスタンス化する必要があります

return ((v1 + v2) + ... ) + vn / static_cast<double>(sizeof...(Ts));

とにかく... MSVCが正しいかどうか...確かに...あなたが欲しい

return (1 + 3) / 2.0;

別の括弧を追加することをお勧めします。

于 2018-02-04T16:00:08.197 に答える