Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 测试所有元素是否等于C++;17倍表达_C++_Templates_Variadic Templates_C++17_Fold Expression - Fatal编程技术网

C++ 测试所有元素是否等于C++;17倍表达

C++ 测试所有元素是否等于C++;17倍表达,c++,templates,variadic-templates,c++17,fold-expression,C++,Templates,Variadic Templates,C++17,Fold Expression,我有一个采用可变参数包的函数,开始时我想检查所有元素的比较是否相等。我能不能用新的C++17倍表达式简洁地编写一行代码?我在想 template<typename... Args> void func (Args... args) { ASSERT ((args == ...)); // more code here... } 模板 无效函数(参数…参数) { 断言((args==…); //更多代码在这里。。。 } 但这不起作用,因为它编译的代码首先正确地比较

我有一个采用可变参数包的函数,开始时我想检查所有元素的比较是否相等。我能不能用新的C++17倍表达式简洁地编写一行代码?我在想

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

    // more code here...
}
模板
无效函数(参数…参数)
{
断言((args==…);
//更多代码在这里。。。
}

但这不起作用,因为它编译的代码首先正确地比较了最后两个参数,然后将最后三个参数与第一个比较的结果(bool)进行比较。这种类型的折叠表达式可能有什么用例(类似于
args<…
)?有没有可能避免编写专门的递归模板来执行此操作?

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

例如,以下函数在所有参数都相等时返回
true

template <typename A0, typename ... Args>
bool foo (A0 const & a0, Args const & ... args)
 { return ( (args == a0) && ... && true ); } 
如果由于某种原因,您无法将
a0
中的
args
和以下
args
拆分

嗯。。。显然,您可以使用前面的
foo()
函数(使用特殊的空版本)

观察
a0
赋值中的初始零,该赋值允许在参数列表为空的情况下使用此解决方案

不幸的是,从前面的
auto a0
赋值中,我得到了很多警告(“表达式结果未使用”,来自clang++),以及“逗号运算符的左操作数无效”,来自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)
 }
分别为
true
false

因此,可以无差别地编写
foo()
bar()
的返回指令

 return ( (args == a0) && ... && true );

sizeof…(args)==0U
的情况下也是如此


<>但是我倾向于忘记这种细节,而喜欢显式的(用最后的<代码>和真/代码>)空的case值。

< p>原因,不幸的是,原因是布尔运算符不像其他语言那样在C++中链接。所以这个表达:

a == (b == c)
(您的折叠表达式将扩展到的内容)将
a
true
false
进行比较,与
b
c
的实际内容无关。我本来希望能增加链接,但显然那部分被删除了

修复方法是,您必须分解比较:

(a == b) && (b == c)
当然,这并不适合折叠,但您可以将所有内容与第一个元素进行比较:

(a == b) && (a == c)
也就是说:

((a0 == args) && ... )
在这一点上,我们只需要能够拉出第一个元素。没问题,这显然就是lambdas的用途:

template <class... Args>
constexpr 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...);
    }
}
模板
constexpr bool all_equal(Args const&…Args){
如果constexpr(sizeof…(Args)==0){
返回true;
}否则{
返回[](自动常量和a0,自动常量和…rest){
收益率((a0==剩余)和&……);
}(args…);
}
}
以下是我在库中的操作方法:

模板
constexpr静态自动相等_v=[]()consteval{
静态断言(sizeof…(values)>0,“gcl::mp::value\u traits::equal\u v:无参数”);
constexpr auto first_value=std::get(std::tuple{values…});
静态断言(
(标准::与&…)相等,
“gcl::mp::value_traits::equal_v:无法比较值”);
返回((值==第一个_值)&&&…);
}();
或者用概念要求替换
static\u assert

模板
概念是否相等?是否可比较=需要(Ts…值)
{
{ 
std::条件_t{}
}->std::与之相同;
};
模板
要求(是否具有可比性)
constexpr静态自动相等_v=[]()consteval{
静态断言(sizeof…(values)>0,“gcl::mp::value\u traits::equal\u v:无参数”);
constexpr auto first_value=std::get(std::tuple{values…});
返回((值==第一个_值)&&&…);
}();

((arg==args)&&&&&…)如果可以在函数参数列表前面加上
arg
,请注意,一元折叠空包的值,特别是使用
&&
,是
真的
(反之,
,用于
|
),因此
条(…)
返回(
返回(
返回((args==a0)&&&…&&true);
)不需要尾随
true
,并且可以简化为
返回((args==a0)&&……)。另外,“注意
a0
赋值中的初始零,该零允许在参数列表为空的情况下使用此解决方案。”@dfri-关于
&&
true
:是的,我知道(现在)这一点,但我倾向于忘记此类细节;我认为最好(对我和其他像我这样健忘的人来说)显式显示默认值(我认为编译器会优化并删除最终的
&&true
);但你是对的,也许我要补充一点。关于“初始零”。。。对不起,我不明白(我的错,我想)你是什么意思)。关于第二部分:可能是我说了“我的错”,因为我不太明白我引用的句子:
0
value w.r.t.能够用空包(
bar()
)调用
bar(…)
,有什么意义?据我所知,初始
0
值(也可以是
-42
)主要用于折叠表达式比较初始包的每个“相邻元素”(例如
a0
本身是一个“移位一”参数包)。但我觉得我可能缺少这一个的逻辑。@dfri-要理解初始零的逻辑,请尝试编译我的完整示例以删除它(使用
auto a0=(…,args));
)。从
bar()
空调用(上次
std::cout
 return ( (args == a0) && ... );
a == (b == c)
(a == b) && (b == c)
(a == b) && (a == c)
((a0 == args) && ... )
template <class... Args>
constexpr 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...);
    }
}