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

Tob*_*ull 10 c++ templates variadic-templates fold-expression c++17

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

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

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

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

Bar*_*rry 19

遗憾的是,不起作用的原因是布尔运算符不像在其他语言中那样在C++中链接.所以表达式:

a == (b == c)
Run Code Online (Sandbox Code Playgroud)

(你的折叠式将扩大到)将比较a要么true或者false,无关什么bc实际上是.我希望这operator<=>会增加链接,但显然那部分被删除了.

修复是你必须打破比较:

(a == b) && (b == c)
Run Code Online (Sandbox Code Playgroud)

当然,这不能很好地折叠,但你可以将所有内容与第一个元素进行比较:

(a == b) && (a == c)
Run Code Online (Sandbox Code Playgroud)

这就是说:

((a0 == args) && ... )
Run Code Online (Sandbox Code Playgroud)

那时,我们只需要能够拉出第一个元素.没问题,这显然是lambdas的用途:

template <class... Args>
bool all_equal(Args const&... args) {
    if constexpr (sizeof...(Args) == 0) {
        return true;
    } else {
        return [](auto const& a0, auto const&... rest){
            return ((a0 == rest) && ...);
        }(args...);
    }
}
Run Code Online (Sandbox Code Playgroud)


max*_*x66 6

正如Piotr Skotnicki所建议的,一个简单的解决方案是将第一个参数与以下参数分开并使用&&折叠算子进行检查

例如,true如果所有参数都是等于,则返回以下函数

template <typename A0, typename ... Args>
bool foo (A0 const & a0, Args const & ... args)
 { return ( (args == a0) && ... && true ); } 
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不适用于空的参数列表

std::cout << foo(1, 1, 1, 1) << std::endl; // print 1
std::cout << foo(1, 1, 2, 1) << std::endl; // print 0
std::cout << foo() << std::endl;           // compilation error
Run Code Online (Sandbox Code Playgroud)

但是你可以添加特殊的空参数 foo()

bool foo ()
 { return true; }
Run Code Online (Sandbox Code Playgroud)

如果出于某种原因,你不能拆分argsa a0和以下args

嗯......你显然可以使用前面的foo()功能(特殊的空版本)

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

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

或者您可以使用带有逗号运算符和赋值的C++ 17 fold表达式,如下所示 bar()

template <typename ... Args>
bool bar (Args const & ... args)
 {
   auto a0 = ( (0, ..., args) );
   return ( (args == a0) && ... && true ); 
 }
Run Code Online (Sandbox Code Playgroud)

观察a0赋值中的初始零,允许使用此解决方案的空参数列表.

不幸的是,从前面的auto a0任务,我得到了很多的警告("表达结果未使用",从铛++,和"逗号操作符的左操作数不起作用",从G ++),我不知道如何避免.

以下是一个完整的工作示例

#include <iostream>

template <typename A0, typename ... Args>
bool foo (A0 const & a0, Args const & ... args)
 { return ( (args == a0) && ... && true ); }

bool foo ()
 { return true; }

template <typename ... Args>
bool bar (Args const & ... args)
 {
   auto a0 = ( (0, ..., args) );
   return ( (args == a0) && ... && true ); 
 }

int main ()
 {
   std::cout << foo(1, 1, 1, 1) << std::endl; // print 1
   std::cout << foo(1, 1, 2, 1) << std::endl; // print 0
   std::cout << foo() << std::endl;           // print 1 (compilation error
                                              //          witout no argument
                                              //          version)

   std::cout << bar(1, 1, 1, 1) << std::endl; // print 1
   std::cout << bar(1, 1, 2, 1) << std::endl; // print 0
   std::cout << bar() << std::endl;           // print 1 (no special version)
 }
Run Code Online (Sandbox Code Playgroud)

- 编辑 -

正如dfri(谢谢!),for和empty args...pack 所指出的,以下折叠表达式的值

( (args == a0) && ... )

( (args == a0) || ... )
Run Code Online (Sandbox Code Playgroud)

分别是truefalse.

所以返回指令foo()并且bar()可以无差别地写

 return ( (args == a0) && ... && true );
Run Code Online (Sandbox Code Playgroud)

要么

 return ( (args == a0) && ... );
Run Code Online (Sandbox Code Playgroud)

这种情况也是如此sizeof...(args) == 0U.

但我倾向于忘记这种细节,而更喜欢明确(最后&& true)空案例值.