标签: fold-expression

Clang和二进制折叠表达式 - 空参数包的诅咒

特别是Clang 3.6.0,目前由Coliru主持.

所有这些片段都来自:

int main() {
    foo();
    std::cout << "\n----\n";
    foo(1, 2, 3);
}
Run Code Online (Sandbox Code Playgroud)

以下代码:

template <class... Args>
void foo(Args... args) {
    std::cout << ... << args;
}
Run Code Online (Sandbox Code Playgroud)

触发以下编译错误:

main.cpp:7:17: error: expected ';' after expression
    std::cout << ... << args;
                ^
                ;
main.cpp:7:15: error: expected expression
    std::cout << ... << args;
              ^
Run Code Online (Sandbox Code Playgroud)

所以我试着在表达式周围添加括号:

(std::cout << ... << args);
Run Code Online (Sandbox Code Playgroud)

它有效,但会触发警告:

main.cpp:7:6: warning: expression result unused [-Wunused-value]
    (std::cout << ... << args);
     ^~~~~~~~~
main.cpp:11:5: note: in instantiation of function template specialization 'foo<>' …
Run Code Online (Sandbox Code Playgroud)

c++ clang compiler-bug fold-expression c++17

12
推荐指数
1
解决办法
971
查看次数

折叠表达式和空参数包:预期结果是什么?

请考虑以下最小示例:

#include<cstddef>

template<std::size_t... I>
constexpr auto sum() { return (I + ...); }

template<bool... B>
constexpr auto check() { return (B && ...); }

int main() {
    static_assert(6 == sum<1,2,3>(), "!");
    // static_assert(0 == sum<>(), "!");
    static_assert(check<true, true>(), "!");
    static_assert(check<>(), "!");
}
Run Code Online (Sandbox Code Playgroud)

注释行不编译.
这同样适用于*代替+.
涉及布尔运算的那个相反.

这里(工作草案)我没有找到关于空参数包的提及.
另一方面,这里(isocpp)似乎是上面例子中的默认结果int().

混合折叠表达式和空参数包时,预期的行为是什么?

c++ templates fold-expression c++17

12
推荐指数
1
解决办法
316
查看次数

折叠表达式的相关性

N4191提出了C++的fold-expressions.有那样的定义

(args + ...)
Run Code Online (Sandbox Code Playgroud)

是左折(即(((a0 + a1) + a2) + ...),那个

(... + args) 
Run Code Online (Sandbox Code Playgroud)

是一个右折(即(... + (a8 + (a9 + a10))).然而,修订后的论文N4295颠倒了左右一元褶的定义.

问题:理由是什么?它似乎更直观(至少当你习惯于从左到右的字母表)从左到右进行评估(args + ...).

c++ associativity language-lawyer fold-expression c++17

11
推荐指数
2
解决办法
278
查看次数

是否可以在折叠表达式中插入额外的操作?

在C++ 17中,fold表达式可用,因此要打印参数,我们可以使用

#define EOL '\n'

template<typename ...Args>
void output_argus(Args&&... args) 
{
    (cout << ... << args) << EOL;
}


int main()
{
    output_argus(1, "test", 5.6f);
}
Run Code Online (Sandbox Code Playgroud)

有输出
1test5.6

如果我想使用fold表达式'\n'为每个元素添加额外的字符以获得以下结果,该怎么办?

1
test
5.6
Run Code Online (Sandbox Code Playgroud)

这甚至可能吗?如果有,怎么样?

c++ templates variadic-templates fold-expression c++17

11
推荐指数
1
解决办法
330
查看次数

为什么左侧折叠表达式不会反转右侧折叠表达式的输出?

我正在看看C++ 17 折叠表达式,我想知道为什么以下程序输出

4 5 6 
4 5 6 
Run Code Online (Sandbox Code Playgroud)

对于这两个for_each电话

template<typename F, typename... T>
void for_each1(F fun, T&&... args)
{
    (fun (std::forward<T>(args)), ...);
}

template<typename F, typename... T>
void for_each2(F fun, T&&... args)
{
    (..., fun (std::forward<T>(args)));
}

int main()
{
     for_each1([](auto i) { std::cout << i << std::endl; }, 4, 5, 6);
     std::cout << "-" << std::endl;
     for_each2([](auto i) { std::cout << i << std::endl; }, 4, 5, 6);
}
Run Code Online (Sandbox Code Playgroud)

Live Example

我认为第二个折叠表达式意味着以相反的顺序输出数字

6 5 4 …
Run Code Online (Sandbox Code Playgroud)

c++ templates c++14 fold-expression

10
推荐指数
1
解决办法
344
查看次数

你能在fold表达式中使用子表达式吗?

以下是合法的表达式吗?

template <std::size_t N, std::size_t... Ix>
bool in_range(std::index_sequence<Ix...>) {
  return ((Ix < N) && ...);
}
Run Code Online (Sandbox Code Playgroud)

它用clang而不是gcc编译

c++ c++11 fold-expression c++17

10
推荐指数
1
解决办法
715
查看次数

使用折叠表达式打印所有可变参数,并在其间使用换行符

C++ 17折叠表达式的经典示例是打印所有参数:

template<typename ... Args>
void print(Args ... args)
{
    (cout << ... << args);
}
Run Code Online (Sandbox Code Playgroud)

例:

print("Hello", 12, 234.3, complex<float>{12.3f, 32.8f});
Run Code Online (Sandbox Code Playgroud)

输出:

Hello12234.3(12.3,32.8)
Run Code Online (Sandbox Code Playgroud)

我想在输出中添加换行符.但是,我找不到一个好方法,到目前为止我找到的最好的方法:

template<typename ... Args>
void print(Args ... args)
{
    (cout << ... << ((std::ostringstream{} << args << "\n").str()));
}
Run Code Online (Sandbox Code Playgroud)

然而,这不是零开销,因为它ostringstream为每个参数构造临时值.

以下版本也不起作用:

(cout << ... << " " << args);

error: expression not permitted as operand of fold expression
Run Code Online (Sandbox Code Playgroud)

(cout << ... << (" " << args));

error: invalid operands to binary expression 
Run Code Online (Sandbox Code Playgroud)

我理解为什么最后两个版本不起作用.使用折叠表达式是否有更优雅的解决方案?

c++ variadic-templates fold-expression c++17

10
推荐指数
2
解决办法
1642
查看次数

测试所有元素是否与C++ 17 fold-expression相同

我有一个函数采用可变参数包,在开始我想检查所有元素比较相等.我可以以某种方式使用新的C++ 17折叠表达式来简洁地编写一个单行程序吗?我刚在想

template<typename... Args>
void func (Args... args)
{
    ASSERT ((args == ...));

    // more code here...
}
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为它编译为首先正确比较后两个参数的代码,然后将第三个参数与第一个比较的结果进行比较,这是一个bool.这种类型的折叠表达式可能具有哪些用例(类似args < ...)?有没有机会我可以避免编写专用的递归模板来执行此操作?

c++ templates variadic-templates fold-expression c++17

10
推荐指数
2
解决办法
2266
查看次数

在MSVC中折叠表达式

我有以下函数来计算平均值:

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

使用VS 2017 15.6.0预览3以下代码

std::cout << mean_of(1, 3);
Run Code Online (Sandbox Code Playgroud)

输出2.5.似乎MSVC将折叠表达式解释为1 + 3 / N而不是(1 + 3) / N.如果我在fold表达式周围添加额外的括号,结果是正确的.使用GCC不需要额外的括号.

这是MSVC中的错误还是我们需要额外的括号?

c++ language-lawyer variadic-templates fold-expression c++17

10
推荐指数
2
解决办法
881
查看次数

在什么基础上,将由单个元素组成的参数包的表达式转换为未表示的表达式

考虑一个例子:

#include <type_traits>

template <class... Ts>
decltype (auto) foo(Ts... ts) {
      return (ts->x + ...);
}

struct X {
    int x;
};

int main() {
    X x1{1};
    static_assert(std::is_reference_v<decltype(foo(&x1))>);
}
Run Code Online (Sandbox Code Playgroud)

[现场演示]

decltype(auto)从带括号的左值推导出的,应根据[cl.type.simple] /4.4推导出左值参考.例如:

decltype(auto) foo(X *x) { // type of result == int&
    return (x->x);
}
Run Code Online (Sandbox Code Playgroud)

但是snipped会触发static_assert.即使我们将表达式组合成额外的括号,例如:

return ((ts->x + ...));
Run Code Online (Sandbox Code Playgroud)

它不会改变效果.

标准中是否有一点可以防止将单个元素的折叠表达式推导到左值参考中?


编辑

作为Johannes Schaub的一个重点- litb clang实际上确实将代码双parens版本解释为带括号的左值并推导出左值引用.在这种情况下,我会将其解释为gcc错误.然而,具有单parens版本的版本仍然存在问题.让我感到困惑的是,至少在多个元素的情况下,必须将版本转换为带括号的代码 - 以实现运算符优先级.例如:

(x + ...)*4 -> (x1 + x2)*4
Run Code Online (Sandbox Code Playgroud)

不一致的原因是什么?

c++ decltype language-lawyer fold-expression c++17

9
推荐指数
1
解决办法
656
查看次数