Home > Enterprise >  C CRTP: how to extend the std::string_view to std::basic_string_view<T> by passing template
C CRTP: how to extend the std::string_view to std::basic_string_view<T> by passing template

Time:02-02

I'm designing a simple parser, which matches patterns. The code use some CRTP C design pattern, I have simplified the code as below.

#include <string_view>

template <typename Base>
struct parser_base {
    constexpr auto operator[](std::string_view& output) const noexcept;
};

struct char_ final : public parser_base<char_> {

    constexpr explicit char_(const char ch) noexcept
        : ch(ch)
    {}

    constexpr inline bool visit(std::string_view& sv) const& noexcept {
        if (!sv.empty() && sv.front() == ch) {
            sv.remove_prefix(1);
            return true;
        }
        return false;
    }

private:
    char ch;
};

template <typename Parser>
constexpr bool parse(std::string_view input, Parser const& parser) noexcept {
    return parser.visit(input);
}

int main()
{
    return 0;
}

You can see that when parsing the std::string_view, it builds correctly.

Now, I would like to extent the std::string_view, which is actually std::basic_string_view<char> to other types, such as I would like to use my own Tokens, so I try to change the code like below:

#include <string_view>

template <typename Base, typename T>
struct parser_base {
    constexpr auto operator[](std::basic_string_view<T>& output) const noexcept;
};

template<typename T>
struct char_ final : public parser_base<char_, T> {

    constexpr explicit char_(const T ch) noexcept
        : ch(ch)
    {}

    constexpr inline bool visit(std::basic_string_view<T>& sv) const& noexcept {
        if (!sv.empty() && sv.front() == ch) {
            sv.remove_prefix(1);
            return true;
        }
        return false;
    }

private:
    T ch;
};

template <typename Parser, typename T>
constexpr bool parse(std::basic_string_view<T> input, Parser const& parser) noexcept {
    return parser.visit(input);
}

int main()
{
    return 0;
}

With the above code, I simply add a second template parameter T (which stands for Token) to the parser_base class, and the following derived class and functions.

But I got the build error:

[ 50.0%] g  .exe -Wall -fexceptions -g  -c F:\code\test_crtp_twoargs\main.cpp -o obj\Debug\main.o
F:\code\test_crtp_twoargs\main.cpp:46:49: error: type/value mismatch at argument 1 in template parameter list for 'template<class Base, class T> struct parser_base'
   46 | struct char_ final : public parser_base<char_, T> {
      |                                                 ^
F:\code\test_crtp_twoargs\main.cpp:46:49: note:   expected a type, got 'char_'

It looks like the struct char_ should not be a class template? But how can I pass the T type to the char_ class?

So, any ideas on how to solve my issue? Thanks.

CodePudding user response:

char_ is not a type it's a template, the type is char_<T>. So

template<typename T>
struct char_ final : public parser_base<char_<T>, T> {
  • Related