c++11generic-programminguser-defined-literals

Length of user-defined string literal as a template argument?


Is there any way to get behavior like this?

// Some definition(s) of operator "" _my_str
// Some definition of function or macro MY_STR_LEN

using T1 = MY_STR_LEN("ape"_my_str);
// T1 is std::integral_constant<std::size_t, 3U>.

using T2 = MY_STR_LEN("aardvark"_my_str);
// T2 is std::integral_constant<std::size_t, 8U>.

It seems not, since the string literals are passed immediately to some_return_type operator "" _my_str(const char*, std::size_t); and never to a literal operator template (2.14.8/5). That size function parameter can't be used as a template argument, even though it will almost always be a constant expression.

But it seems like there ought to be some way to do this.


Update: The accepted answer, that this is not possible without an extra definition per literal, is accurate for C++11 as asked, and also C++14 and C++17. C++20 allows the exact result asked for:

#include <cstdlib>
#include <type_traits>
#include <string_view>

struct cexpr_str {
    const char* ptr;
    std::size_t len;

    template <std::size_t Len>
    constexpr cexpr_str(const char (&str)[Len]) noexcept
    : ptr(str), len(Len) {}
};

// Essentially the same as
// std::literals::string_view_literals::operator""sv :
template <cexpr_str Str>
constexpr std::string_view operator "" _my_str () noexcept
{
     return std::string_view(Str.ptr, Str.len);
}

#define MY_STR_LEN(sv) \
  std::integral_constant<std::size_t, (sv).size()>

Solution

  • Reading C++11 2.14.8 carefully reveals that the "literal operator template" is only considered for numeric literals, but not for string and character literals.

    However, the following approach seems to give you constexpr access to the string length (but not the pointer):

    struct MyStr
    {
        char const * str;
        unsigned int len;
        constexpr MyStr(char const * p, unsigned int n) : str(p), len(n) {}
    };
    
    constexpr MyStr operator "" _xyz (char const * s, unsigned int len)
    {
        return MyStr(s, len);
    }
    
    constexpr auto s = "Hello"_xyz;
    

    Test:

    #include <array>
    
    using atype = std::array<int, s.len>; // OK