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

C++ Comparison between template parameters seems to be ignored

本文关键字:比较 被忽略了 之间 参数 C++      更新时间:2023-10-16
// 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>();

有人能向我解释为什么会发生这种情况,并帮助我找到解决这个问题的方法吗?非常感谢!

问题的原因很简单,三元运算符评估太迟:

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

以及template::type>constexpr auto do_substr(参数…Cr({return substr((}

并调用它来代替三元运算符:

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

由于我不知道你的代码在做什么,我避免了完美地转发参数包,但可以随意使用

do_substr(Params && ...Cr)

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