Can anyone tell me why this doesn't work?
template<char... cs> struct StaticString {};
template<char... tail, char... prefix>
constexpr bool startsWith(StaticString<prefix..., tail...>, StaticString<prefix...>)
{
return true;
}
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'a'>()),
"ab starts with a");
Why is tail deduced to be empty?
From cpprefrence - Parameter pack
Explanation
...
In a primary class template, the template parameter pack must be the final parameter in the template parameter list.
In a function template, the template parameter pack may appear earlier in the list provided that all following parameters can be deduced from the function arguments, or have default arguments
and cppreference - Template argument deduction
Deduction from a type
...
If P has one of the forms that include a template parameter list<T>
or<I>
, then each element Pi of that template argument list is matched against the corresponding template argument Ai of its A. If the last Pi is a pack expansion, then its pattern is compared against each remaining argument in the template argument list of A.A trailing parameter pack that is not otherwise deduced, is deduced to an empty parameter pack.
To make this work, the compiler must be able to deduce the parameters. This may be done through overloads of startsWith
with varying template parameters. You can start with the final part, where only the first StaticString
has any remaining arguments left
template<char... tail>
constexpr bool startsWith(StaticString<tail...>, StaticString<>)
{
return true;
}
You then have a failing startsWith
, where both StaticString
s differ
template<char... tail1, char... tail2>
constexpr bool startsWith(StaticString<tail1...>, StaticString<tail2...>)
{
return false;
}
and finally an overload where the prefix is stripped off and the remaining parts compared
template<char prefix, char... tail1, char... tail2>
constexpr bool startsWith(StaticString<prefix, tail1...>, StaticString<prefix, tail2...>)
{
return startsWith(StaticString<tail1...>(), StaticString<tail2...>());
}
Now you can static_assert
with various arguments, e.g.
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");
will result in (Ubuntu 16.04, g++ 5.4)
a.cpp:23:1: error: static assertion failed: ab does not start with ac
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'a', 'c'>()), "ab does not start with ac"
^
a.cpp:24:1: error: static assertion failed: ab does not start with xa
static_assert(startsWith(StaticString<'a', 'b'>(), StaticString<'x', 'a'>()), "ab does not start with xa"
^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With