带空参数包的一元折叠
Unary fold with empty parameter pack
#include <iostream>
#include <utility>
template<std::size_t... items>
constexpr std::size_t count()
{
return std::index_sequence<items...>().size();
}
template<std::size_t... items>
constexpr std::size_t fold_mul()
{
if( count<items...>() == 0 )
{
return 1;
}
else
{
return (... * items);
}
}
int main()
{
std::cout << "Result: " << fold_mul<>() << "\n";
}
此代码应输出 1
但会抛出错误:
<source>:19:28: error: fold of empty expansion over operator*
19 | return (... * items);
我的问题是: 为什么这行不通,因为 fold_expression 显然在 else
部分。
作为参考,此实现有效:
template<typename... Args>
constexpr std::size_t fold_mul();
template<std::size_t... j>
requires (count<j...>() > 0)
constexpr std::size_t fold_mul()
{
return (j * ...);
}
template<>
constexpr std::size_t fold_mul()
{
return 1;
}
问题是,指定空展开的折叠表达式时,(... * items)
编译时无效;即使它不会在 运行 时间进行评估。
你可以使用 constexpr if (C++17 起);那么else部分在被指定为空扩展的折叠表达式时将被丢弃。
If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
template<std::size_t... items>
constexpr std::size_t count()
{
return std::index_sequence<items...>().size();
}
template<std::size_t... items>
constexpr std::size_t fold_mul()
{
if constexpr ( count<items...>() == 0 )
// ^^^^^^^^^
{
return 1;
}
else
{
return (... * items);
}
}
唯一具有空序列默认值的折叠表达式是&&
(默认为true
),||
(默认为false
),和 ,
(默认为 void()
)。
就语言而言,*
没有默认值。但是在这种情况下,我们可以使用二元折叠而不是一元折叠:
template<std::size_t... items>
constexpr std::size_t fold_mul()
{
return (1 * ... * items);
}
这适用于空情况(值只是 1
)和非空情况(因为 1
是乘法的单位元素,所以不改变值).
#include <iostream>
#include <utility>
template<std::size_t... items>
constexpr std::size_t count()
{
return std::index_sequence<items...>().size();
}
template<std::size_t... items>
constexpr std::size_t fold_mul()
{
if( count<items...>() == 0 )
{
return 1;
}
else
{
return (... * items);
}
}
int main()
{
std::cout << "Result: " << fold_mul<>() << "\n";
}
此代码应输出 1
但会抛出错误:
<source>:19:28: error: fold of empty expansion over operator*
19 | return (... * items);
我的问题是: 为什么这行不通,因为 fold_expression 显然在 else
部分。
作为参考,此实现有效:
template<typename... Args>
constexpr std::size_t fold_mul();
template<std::size_t... j>
requires (count<j...>() > 0)
constexpr std::size_t fold_mul()
{
return (j * ...);
}
template<>
constexpr std::size_t fold_mul()
{
return 1;
}
问题是,指定空展开的折叠表达式时,(... * items)
编译时无效;即使它不会在 运行 时间进行评估。
你可以使用 constexpr if (C++17 起);那么else部分在被指定为空扩展的折叠表达式时将被丢弃。
If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
template<std::size_t... items>
constexpr std::size_t count()
{
return std::index_sequence<items...>().size();
}
template<std::size_t... items>
constexpr std::size_t fold_mul()
{
if constexpr ( count<items...>() == 0 )
// ^^^^^^^^^
{
return 1;
}
else
{
return (... * items);
}
}
唯一具有空序列默认值的折叠表达式是&&
(默认为true
),||
(默认为false
),和 ,
(默认为 void()
)。
*
没有默认值。但是在这种情况下,我们可以使用二元折叠而不是一元折叠:
template<std::size_t... items>
constexpr std::size_t fold_mul()
{
return (1 * ... * items);
}
这适用于空情况(值只是 1
)和非空情况(因为 1
是乘法的单位元素,所以不改变值).