Search code examples
c++templatesvariadic-templatesc++20

Creating variadic template with template object containing string


I want to create a template that will take variadic number of a specific class that contains a string. When i try to make such a template class, it throws no instance of constructor "A" matches the argument list

class A:

template<template_string s>
class A {};

class B:

template<A... As>
class B {};

template_string.h:

template<size_t _N>
struct template_string {
char c_str[_N];

    constexpr template_string(const char(&text)[_N]) {
        std::copy(text, text+_N, c_str);
    }

    constexpr std::string std_str() const noexcept {
        return std::string(c_str);
    }
    constexpr std::string_view str_view() const noexcept {
        return std::string_view(c_str);
    }

    constexpr size_t length() const noexcept {
        return _N-1;
    }

};

I want to make it explicitly through templates and classes. What would i need to do so that I can construct class B like this:

B<A<"text">(), A<"other text">(),....> b;

Solution

  • This is an instance of the "most vexing parse" problem, where it looks like you are declaring a function type instead of creating on object. Here's a complete working example, where I've replaced the function call () with the uniform initialization syntax {}:

    #include <cstddef>
    #include <string>
    
    using std::size_t;
    
    template<size_t _N> requires (_N >= 1)
    struct template_string {
        char c_str[_N];
    
        constexpr template_string(const char(&text)[_N]) {
            std::copy(text, text+_N, c_str);
        }
    
        constexpr std::string std_str() const noexcept {
            return std::string(c_str);
        }
        constexpr std::string_view str_view() const noexcept {
            return std::string_view(c_str, length());
        }
    
        constexpr size_t length() const noexcept {
            return _N-1;
        }
    
    };
    
    
    template<template_string s>
    class A {};
    
    template<A... As>
    class B {};
    
    int
    main()
    {
        [[maybe_unused]] B<A<"text">{}, A<"other text">{}> b;
    }
    

    The other thing I did was create the string_view with the length of the string, just in case the string contains NUL bytes, as in "hello\0there".