【问题标题】:Unary fold with empty parameter pack具有空参数包的一元折叠
【发布时间】:2021-05-13 21:23:24
【问题描述】:
#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,但会引发错误:

:19:28: 错误:操作符上的空扩展折叠*
19 |返回(... * 项);

我的问题是:为什么这不起作用,因为 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;
}

【问题讨论】:

  • 你知道吗,你可以简单地使用sizeof...(Args)来获取Args的长度?

标签: c++ variadic-templates c++20 fold


【解决方案1】:

问题是,当指定带有空扩展的折叠表达式时,(... * items) 在编译时是无效的;即使它不会在运行时进行评估。

您可以使用constexpr if(C++17 起);那么else部分在被指定为空展开的折叠表达式时将被丢弃。

如果值为 true,则丢弃 statement-false(如果存在),否则丢弃 statement-true

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);
    }
}

【讨论】:

  • 非常简洁,我以前不知道这个!
  • 或者干脆return (1 * ... * items); :-)
【解决方案2】:

唯一具有空序列默认值的折叠表达式是&amp;&amp;(默认为true)、||(默认为false)和,(默认为void() )。

* 就语言而言没有默认值。但在这种情况下,我们可以使用二元折叠而不是一元折叠:

template<std::size_t... items>
constexpr std::size_t fold_mul()
{
    return (1 * ... * items);
}

这适用于空情况(值只是1)和非空情况(因为1 是乘法的标识元素,因此不会更改值)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多