来自cpprefrence - Parameter pack
说明
...
在主类模板中,模板参数包必须是模板参数列表中的最后一个参数。
在函数模板中,模板参数包可以出现在参数列表中较早的位置,前提是所有随后的参数可以从函数参数中推导出来,或者具有默认参数。
以及cppreference - Template argument deduction
来自类型的推导
...
如果P具有包括模板参数列表<T>
或<I>
的形式之一,则该模板参数列表的每个元素Pi与其A的相应模板参数Ai匹配。如果最后的Pi是一个模板参数包扩展,那么它的模式将与A的模板参数列表中的每个剩余参数进行比较。
未被推导出的尾部参数包将被推导为空参数包。
为了使其工作,编译器必须能够推导出参数。这可以通过使用具有不同模板参数的startsWith
重载来完成。您可以从最后一部分开始,其中仅第一个StaticString
具有任何剩余参数。
template<char... tail>
constexpr bool startsWith(StaticString<tail...>, StaticString<>)
{
return true;
}
你遇到了一个失败的startsWith
,其中两个StaticString
不同。
template<char... tail1, char... tail2>
constexpr bool startsWith(StaticString<tail1...>, StaticString<tail2...>)
{
return false;
}
最后,当前缀被剥离后,比较其余部分的重载函数将会被执行。
template<char prefix, char... tail1, char... tail2>
constexpr bool startsWith(StaticString<prefix, tail1...>, StaticString<prefix, tail2...>)
{
return startsWith(StaticString<tail1...>(), StaticString<tail2...>());
}
现在你可以使用各种参数来进行static_assert
,例如:
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'a'>()),
"ab starts with a");
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'a', 'b'>()),
"ab starts with ab");
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'a', 'c'>()),
"ab does not start with ac");
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'x', 'a'>()),
"ab does not start with xa");
将导致 (Ubuntu 16.04, g++ 5.4) 出现以下错误:
a.cpp:23:1: 错误:静态断言失败:ab 不以 ac 开头
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'a', 'c'>()), "ab does not start with ac"
^
a.cpp:24:1: 错误:静态断言失败:ab 不以 xa 开头
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'x', 'a'>()), "ab does not start with xa"
^