MSVC 中的折叠表达式
Fold expressions in MSVC
我有以下计算平均值的函数:
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 将折叠表达式解释为 1 + 3 / N
而不是 (1 + 3) / N
。如果我在折叠表达式周围添加额外的括号,结果是正确的。使用 GCC 不需要额外的括号。
这是 MSVC 中的错误还是我们需要额外的括号?
有趣的问题。
纠正我的第一个解释,在我看来,g++ 和 clang++ 是正确的,而 MSVC 是错误的。
我想这是因为在 C++17 的 n4659 草案中(抱歉:我无法访问最终版本)我看到表达式规则 (A.4) 其中除法运算符涉及“乘法表达式”规则如下
multiplicative-expression / pm-expression
一个“multiplicative-expression”也可以是一个“pm-expression”,它可以是一个“” cast-expression”可以是“unary-expression”可以是“postfix-expression”一个“primary-expression”可以是一个“fold-expression”
所以规则可以看成
fold-expression / pm-expression
所以,如果我没记错的话,“fold-expression”应该在应用除法之前作为一个整体求值。
我的第一个解释(MSVC 正确,g++ 和 clang++ 错误)是基于 17.5.3 的仓促讲座
The instantiation of a fold-expression produces:
(9.1) ((E1 op E2) op ···) op EN for a unary left fold
和 8.1.6
An expression on the form (... op e) where op is a fold-operator is called a unary left fold.
所以我认为
return (... + values) / static_cast<double>(sizeof...(Ts));
应该实例化
return ((v1 + v2) + ... ) + vn / static_cast<double>(sizeof...(Ts));
无论如何...是否正确的 MSVC...确定...您想要
return (1 + 3) / 2.0;
我建议你再添加一对括号。
这是 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);
(这两个 GCC and clang 都能很好地编译,但会触发 MSVC 中的所有四个 static_assert
)并在内部归档。
20180205 更新:此错误已在 Visual C++ 的未来版本中修复。
我有以下计算平均值的函数:
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 将折叠表达式解释为 1 + 3 / N
而不是 (1 + 3) / N
。如果我在折叠表达式周围添加额外的括号,结果是正确的。使用 GCC 不需要额外的括号。
这是 MSVC 中的错误还是我们需要额外的括号?
有趣的问题。
纠正我的第一个解释,在我看来,g++ 和 clang++ 是正确的,而 MSVC 是错误的。
我想这是因为在 C++17 的 n4659 草案中(抱歉:我无法访问最终版本)我看到表达式规则 (A.4) 其中除法运算符涉及“乘法表达式”规则如下
multiplicative-expression / pm-expression
一个“multiplicative-expression”也可以是一个“pm-expression”,它可以是一个“” cast-expression”可以是“unary-expression”可以是“postfix-expression”一个“primary-expression”可以是一个“fold-expression”
所以规则可以看成
fold-expression / pm-expression
所以,如果我没记错的话,“fold-expression”应该在应用除法之前作为一个整体求值。
我的第一个解释(MSVC 正确,g++ 和 clang++ 错误)是基于 17.5.3 的仓促讲座
The instantiation of a fold-expression produces:
(9.1) ((E1 op E2) op ···) op EN for a unary left fold
和 8.1.6
An expression on the form (... op e) where op is a fold-operator is called a unary left fold.
所以我认为
return (... + values) / static_cast<double>(sizeof...(Ts));
应该实例化
return ((v1 + v2) + ... ) + vn / static_cast<double>(sizeof...(Ts));
无论如何...是否正确的 MSVC...确定...您想要
return (1 + 3) / 2.0;
我建议你再添加一对括号。
这是 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);
(这两个 GCC and clang 都能很好地编译,但会触发 MSVC 中的所有四个 static_assert
)并在内部归档。
20180205 更新:此错误已在 Visual C++ 的未来版本中修复。