C++ 测试所有元素是否等于C++;17倍表达
我有一个采用可变参数包的函数,开始时我想检查所有元素的比较是否相等。我能不能用新的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==…); //更多代码在这里。。。 } 但这不起作用,因为它编译的代码首先正确地比较
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...);
}
}