Search code examples
c++stringclassaggregate-initialization

I'm trying to make a string class with static memory array


This is just for fun, I know i can use the std and not reinvent the wheel, etc.

This is essentially my class:

template<size_t size>
class sstring {
public:
    char buffer[size];
};

I want to be able to use it like this:

sstring<> str1 = "My string";      // One possible way
sstring str2 = "My other string";  // Another possible way

But the closest i get is: sstring<n> str = { "..." };, I don't quite understand why it cannot infer the size by itself and I would like it to do so.

Without templates I get a bit closer: sstring str = { "..." };.

I realized it happens because that's how aggregate initialization works, so i tried with a public constructor, but lost the aggregate advantages.

Then tried to overload the = operator, but still get the aggregate construction syntax.

I want to keep my class as an aggregate type and be able to construct it as any of the 'possible' examples above.

I would also like to keep the template so i can provide the size in case i can't / don't want to provide the value immediately, but it's not necessary.


Solution

  • Disclaimer: I missed the aggregate part of the question. I will leave this answer nevertheless as you might not be aware of CTAD.

    If you write a constructor that accepts a reference to a c-string you can make use of Class template argument deduction:

    #include <cstddef>
    #include <algorithm>
    
    template<size_t size>
    class sstring {
    public:
        sstring(const char (&b)[size]) {
            std::copy(b,b+size,buffer);
        }
        char buffer[size];
    };
    
    int main() {
        sstring foo = "asd";
    }
    

    Live Demo

    The explicit deduction guide would be

    template <size_t size>
    sstring(const char (&b)[size]) -> sstring<size>;
    

    I cannot completely explain why the constructor is needed. It has to do with array to pointer decay. Without the constructor you can get this though:

    #include <cstddef>
    #include <algorithm>
    
    template<size_t size>
    class sstring {
    public:
        char buffer[size];
    };
    
    template<class... U >
    sstring(U... ) -> sstring<1 + sizeof...(U)>;
    
    int main() {
        sstring foo{'a','b','c'};
    }
    

    Inpsired from the deduction guide for std::array (https://en.cppreference.com/w/cpp/container/array/deduction_guides)