C ++模板参数之间的比较似乎被忽略了

时间:2018-07-20 19:29:22

标签: c++ templates recursion template-meta-programming

// III
template <
    size_t N_CURRENT,
    size_t N_END,
    size_t N_BEGIN = N_CURRENT,
    char ... Cr,
    size_t SUBSTRING_LENGTH = N_END - N_BEGIN
>
constexpr static_string substr() const noexcept {
    static_assert(N_END >= N_CURRENT, "static_string::substr(): N_END 
must be more than or equal to N_CURRENT!");

return N_CURRENT == N_END
    ? static_string(SUBSTRING_LENGTH, Cr...)
    : substr<N_CURRENT+1, N_END, N_BEGIN, Cr..., ' '>(); //causes a lot of recursion errors...
    // note the ' ' in substr<N_CURRENT+1, B_END, B_BEGIN, Cr..., ' '> has been added for testing purposes.
}

对不起,标题有点含糊:我不知道到底是什么问题。 然而: 表达式N_CURRENT == N_END似乎被忽略,并且使用了后者的返回值。即使我将N_CURRENT == N_END更改为true,后者仍在使用。仅当我实际调用该函数时才会显示错误,例如

static_string str = str1.substr<4, 7>();

有人可以向我解释为什么会这样,并帮助我找到解决该问题的方法吗?非常感谢!

1 个答案:

答案 0 :(得分:2)

问题的原因很简单,三元运算符的评估为时已晚:

N_CURRENT == N_END
    ? static_string(SUBSTRING_LENGTH, Cr...)
    : substr<N_CURRENT+1, N_END, N_BEGIN, Cr..., ' '>()

这意味着仅在实例化以下条件之后才检查条件:

substr<N_CURRENT+1, N_END, N_BEGIN, Cr..., ' '>

三元运算符可以避免执行错误的路径,但不能避免编译。 为了使其正常工作,您应该使用以下C ++ 17功能:

if constexpr(N_CURRENT == N_END)
  return static_string(SUBSTRING_LENGTH, Cr...);
else
  return substr<N_CURRENT+1, N_END, N_BEGIN, Cr..., ' '>()

这样,else部分仅被部分解析,而没有实例化substr<>()

如果编译器不支持c ++ 17的if constexpr,则必须针对不同的情况编写不同的功能,并使用std::enable_if启用/禁用它们。 (由于我真的不知道其余代码的工作方式,所以我只是在猜测您的代码的外观。特别是,我不知道Cr ...是什么,所以很可能我做错了。我建议您接受这些想法并与他们合作。) std::enable_if应该在您的代码上起作用:

template <int N_CURRENT,
          int N_END, int N_BEGIN,
          int SUBSTRING_LENGTH,
          class ...Params, 
          class = typename std::enable_if<N_CURRENT == N_END>::type >
constexpr auto do_substr(Params ...Cr)
{
   return static_string(SUBSTRING_LENGTH, Cr...);
}

和     模板::类型>     constexpr auto do_substr(参数... Cr)     {         返回substr()     }

并调用它而不是三元运算符:

return do_substr<N_CURRENT, N_END, N_BEGIN, Params...>(Cr...);

由于我不知道您的代码在做什么,因此我避免了参数包的完美转发,但是请随时使用

do_substr(Params && ...Cr)

std::forward<Params>(Cr)...