How to define a contructor for <...auto...>

Viewed 97

With the following program, which is an extract from something larger that I'm experimenting with, I get an error message that seems to be related to the constructor for fixed_string

#include <string>
#include <cstring>

template<std::size_t N>
struct fixed_string {
    static const constexpr std::size_t size__ = N;

    constexpr fixed_string(char const* s) :
            buf("") {
        for (std::size_t i = 0; i <= N; ++i)
            buf[i] = s[i];
    }
    constexpr operator char const*() const {
        return buf;
    }
    constexpr bool operator==(const char* other) const {
        return ::strncmp(buf, other, N) == 0;
    }
    template<std::size_t M>
    constexpr bool compare(const fixed_string<M>& other) const {
        return (N == M && ::strncmp(buf, other.buf, N) == 0) ? std::true_type(): std::false_type();
    }

    char buf[N + 1];
};

template<std::size_t N>
fixed_string(char const (&)[N]) -> fixed_string<N - 1>;

////////////////////////////////////////////

template<fixed_string TARGET_NAME, fixed_string THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));

template<fixed_string NAME, typename TYPE>
class Member {
public:
    static const constexpr fixed_string name__ { NAME };

public:
    template<fixed_string TARGET_NAME>
    const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
        return member_;
    }

protected:
    TYPE member_;
};

template<typename ... MEMBERS>
class Container: public MEMBERS... {
};

The error messages are:

../src/test-concepts.cpp:43:35: error: class template argument deduction failed:
   43 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:43:35: error: no matching function for call to ‘fixed_string(fixed_string<...auto...>)’
../src/test-concepts.cpp:8:12: note: candidate: ‘template<long unsigned int N> fixed_string(const char*)-> fixed_string<N>’
    8 |  constexpr fixed_string(char const* s) :
      |            ^~~~~~~~~~~~
../src/test-concepts.cpp:8:12: note:   template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note:   couldn’t deduce template parameter ‘N’
   43 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:5:8: note: candidate: ‘template<long unsigned int N> fixed_string(fixed_string<N>)-> fixed_string<N>’
    5 | struct fixed_string {
      |        ^~~~~~~~~~~~
../src/test-concepts.cpp:5:8: note:   template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note:   mismatched types ‘fixed_string<N>’ and ‘fixed_string<...auto...>’
   43 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:28:1: note: candidate: ‘template<long unsigned int N> fixed_string(const char (&)[N])-> fixed_string<(N - 1)>’
   28 | fixed_string(char const (&)[N]) -> fixed_string<N - 1>;
      | ^~~~~~~~~~~~
../src/test-concepts.cpp:28:1: note:   template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note:   mismatched types ‘const char [N]’ and ‘fixed_string<...auto...>’
   43 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:43: confused by earlier errors, bailing out

This is part of a project using templates that overloads a given function (get in this case), for which there is only one suitable candidate that fulfils the constraint. The value that the constraint operates on is a name - a string literal - not a const string variable, which is passed as a non-type parameter to an instantiation of the template: something like:

Container<Member<"fred", std::string>, Member<"bert", int>, Member<"alfie", bool>> some_values;

I want to be able to retrieve a value using something like

int result = some_values.get<"bert">();

I have had difficulty finding much information about the "<...auto...>" specialisation of the template. I presume this is an internal representation used by gcc for constant, non-type values.

The error messages point me to the lack of a suitable overloaded constructor for fixed_string. What should this be?

1 Answers

The problem I see is that fixed_string is a template class, not a class.

So, when you define a concept as

template<fixed_string TARGET_NAME, fixed_string THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));

you have that fixed_string TARGET_NAME (fixed_string THIS_NAME also) doesn't works because fixed_string isn't a type. I mean: fixed_string<5> is a type, not fixed_string.

I know that you have a deduction guide that, given the literal string, deduce the template parameter for the fixed_string, but remain the problem that the concept should works with elements of different types (fixed_string of different lengths).

I suppose you can solve the problem with auto

template <auto TARGET_NAME, auto THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));

but, when you declare Member, you have the same problem: fixed_string NAME doesn't works because fixed_sting (without a length) isn't a type.

template<fixed_string NAME, typename TYPE>
class Member

Unfortunately, if you use auto

template <auto NAME, typename TYPE>
class Member

defining a Member with a literal string argument (Member<"bert", int>, by example), nothing bring "bert" to a fixed_string.

Suggestion: what about a fixed_string without a template argument?

Related