简体   繁体   中英

How to get string length at compile time if possible?

Consider a BasicCharp class with two constructors:

template <class CharType>
class BasicCharp {
    public:
        using value_type    = CharType;
        using pointer       = value_type*;
        public:
//1
            template<size_t SIZE>
            constexpr BasicCharp(value_type (&str)[SIZE]) noexcept
                : m_Length(SIZE)
                , m_String(str) {}
//2
            constexpr BasicCharp(pointer string) noexcept
                : m_Length(countElems(string))
                , m_String(string) {}
        private:
        size_t m_Length;
        pointer m_String;
};

Constructing:

BasicCharp<const char> str = "test";

This calls constructor 2, however if there is no constructor 2, this does call constructor 1.

How to keep constructor 2, but enforce using constructor 1 if possible?

A c++17 solution is preferred, but any standart is welcome.

The goal is to deduce string literal's size at compile time, but if a pointer is passed, size should be calculated by the constructor.

Not exactly the same, but you might tag dispatch, something like:

template <typename > struct Tag{};


template <class CharType>
class BasicCharp {
// ...
public:
    template<typename T>
    constexpr BasicCharp(const T& str) noexcept : BasicCharp(str, Tag<T>{})
    {
        // Or alternatively, use if constexpr here
    }

private:
    template<std::size_t SIZE>
    constexpr BasicCharp(const value_type (&str)[SIZE],
                         Tag<value_type[SIZE]>) noexcept
        : m_Length(SIZE)
        , m_String(str) {}

    constexpr BasicCharp(const value_type*string, Tag<const value_type*>) noexcept
        : m_Length(countElems(string))
        , m_String(string) {}
};

Your overloads are ambiguous; a decayed array pointer is no better or worse candidate than a non-decayed one. It only compiles because non-template overloads are a better match than template ones.

What you can do is make the pointer overload a worse overload candidate, eg by introducing a user-defined conversion sequence.

        struct ptr { pointer p; ptr(pointer p) : p(p) {} };

        constexpr BasicCharp(ptr string) noexcept
            : m_Length(countElems(string.p))
            , m_String(string.p) {}

You can assign the result to constexpr variable, but it is not 100% garanted that this will be done compile time, also you can use consteval, in this case if variable isn't assigned compile time you will get error(consteval works from c++20)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM