【问题标题】:constexpr && doesn't short-circuit?constexpr && 不会短路?
【发布时间】:2023-01-25 15:00:47
【问题描述】:

以下代码尝试根据参数包中传递的最后一个参数做出编译时决策。如果参数包参数的数量> 0,它包含一个比较,然后尝试获取它的最后一个元素。但是,构造的元组是在一个无效索引处访问的,我想这是因为它在第二次调用 foo() 时为 -1。我是否误认为 constexpr && 没有像它应该的那样短路?

Demo

#include <cstdio>
#include <concepts>
#include <utility>
#include <tuple>


template <typename... Args>
auto foo(Args&&... args)
{
    auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
    constexpr std::size_t cnt = sizeof...(Args);

    if (cnt > 0 && std::same_as<std::remove_cvref_t<std::tuple_element_t<cnt-1, decltype(tuple)>>, int>) {
        printf("last is int\n");
    } else {
        printf("last is not int\n");
    }
}

int main()
{
    foo(2);

    foo();
}

错误:

/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple: In instantiation of 'struct std::tuple_element<18446744073709551615, std::tuple<> >':
<source>:13:25:   required from 'auto foo(Args&& ...) [with Args = {}]'
<source>:24:8:   required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple:1357:25: error: static assertion failed: tuple index must be in range
 1357 |       static_assert(__i < sizeof...(_Types), "tuple index must be in range");
      |                     ~~~~^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple:1357:25: note: the comparison reduces to '(18446744073709551615 < 0)'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple:1359:13: error: no type named 'type' in 'struct std::_Nth_type<18446744073709551615>'
 1359 |       using type = typename _Nth_type<__i, _Types...>::type;
      |             ^~~~

【问题讨论】:

  • 除了 cnt 之外,没有其他 constexpr 允许代码“做出编译时决定”。您添加了 if-constexpr 标签,但没有使用 if constexpr
  • @Someprogrammerdude ...尽管将if 更改为if constexpr 没有帮助...

标签: c++ tuples if-constexpr and-operator


【解决方案1】:

您可以强制编译器仅在 cnt &gt; 0 使用 if constexpr(自 c++17 起可用)并分成 2 个嵌套的 ifs 时才评估第二个条件:

#include <cstdio>
#include <concepts>
#include <utility>
#include <tuple>

template <typename... Args>
auto foo(Args&&... args)
{
    auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
    constexpr std::size_t cnt = sizeof...(Args);

//-----vvvvvvvvv---------
    if constexpr (cnt > 0)
    {
        if (std::same_as<std::remove_cvref_t<std::tuple_element_t<cnt - 1, decltype(tuple)>>, int>) {
            printf("last is int
");
        }
        else {
            printf("last is not int
");
        }
    }
}

int main()
{
    foo(2);
    foo();
}

输出:

last is int

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2011-04-12
    • 2011-03-10
    • 1970-01-01
    相关资源
    最近更新 更多