Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<string>: basic_string<unicorn>::find_meow_of family with std::char_traits<unicorn> specialization are not supported #4930

Open
AlexGuteniev opened this issue Sep 3, 2024 · 0 comments · May be fixed by #4951
Labels
bug Something isn't working

Comments

@AlexGuteniev
Copy link
Contributor

Describe the bug

Discovered when trying to make follow up optimizations after #4744

basic_string with odd types and char_traits specialization in std:: can exist.
From [namespace.std]/2 :

Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace std provided that

  • the added declaration depends on at least one program-defined type, and
  • the specialization meets the standard library requirements for the original template

However with std::char_traits<unicorn> specialization provided, basic_string<unicorn>::find_first_of fails to compile here:

static_assert(is_unsigned_v<_Elem>,
"Standard char_traits is only provided for char, wchar_t, char16_t, and char32_t. See N4950 [char.traits]. "
"Visual C++ accepts other unsigned integral types as an extension.");

Command-line test case

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.12.0-pre.1.0
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

C:\Program Files\Microsoft Visual Studio\2022\Preview>cd %temp%

C:\Users\ALEXG~1\AppData\Local\Temp>type repro.cpp
#include <cassert>
#include <string>

static constexpr unsigned char odd_mask = 0xF;

enum odd_char : unsigned char {};

namespace std {
    template <>
    class char_traits<odd_char> {
    public:
        using char_type  = odd_char;
        using int_type   = int;
        using off_type   = streamoff;
        using pos_type   = streampos;
        using state_type = mbstate_t;

        static bool eq(const char_type c, const char_type d) {
            return ((static_cast<unsigned char>(c) ^ static_cast<unsigned char>(d)) & odd_mask) == 0;
        }

        static bool lt(const char_type c, const char_type d) {
            return (static_cast<unsigned char>(c) & odd_mask) < (static_cast<unsigned char>(d) & odd_mask);
        }

        static int compare(const char_type* const c, const char_type* const d, const size_t n) {
            for (size_t i = 0; i != n; ++i) {
                int ci = static_cast<unsigned char>(c[i]) & odd_mask;
                int di = static_cast<unsigned char>(d[i]) & odd_mask;
                int r  = ci - di;
                if (r != 0) {
                    return r;
                }
            }

            return 0;
        }

        static size_t length(const char_type* const p) {
            const char_type* c = p;
            while (static_cast<unsigned char>(*c) != 0) {
                ++c;
            }

            return static_cast<size_t>(c - p);
        }

        static const char_type* find(const char_type* p, const size_t n, const char_type c) {
            for (size_t i = 0; i != n; ++i) {
                if (eq(p[i], c)) {
                    return p + i;
                }
            }

            return nullptr;
        }

        static char_type* move(char_type* s, const char_type* p, const size_t n) {
            memmove(s, p, n);
            return s;
        }

        static char_type* copy(char_type* s, const char_type* p, const size_t n) {
            memmove(s, p, n);
            return s;
        }

        static void assign(char_type& r, const char_type& d) {
            r = d;
        }
        static char_type* assign(char_type* const s, const std::size_t n, const char_type c) {
            memset(s, static_cast<unsigned char>(c), n);
            return s;
        }

        static bool not_eof(int) {
            return true;
        }

        static char_type to_char_type(const int_type i) {
            return char_type(static_cast<unsigned char>(i));
        }

        static int_type to_int_type(const char_type i) {
            return static_cast<unsigned char>(i);
        }

        static bool eq_int_type(const int_type c, const int_type d) {
            if (c == -1) {
                return d == -1;
            } else {
                return ((c ^ d) & odd_mask) == 0;
            }
        }

        static int_type eof() {
            return -1;
        }
    };
}; // namespace std

using odd_string = std::basic_string<odd_char>;

int main() {
    const odd_char s_init[] = {static_cast<odd_char>(0x55), static_cast<odd_char>(0x44), static_cast<odd_char>(0x33),
        static_cast<odd_char>(0x22), static_cast<odd_char>(0x11), static_cast<odd_char>(0)};
    odd_string s(s_init);

    assert(s.length() == 5);
    assert(s.find(static_cast<odd_char>(0x54)) == 1);
    assert(s.find(static_cast<odd_char>(0x26)) == s.npos);

    const odd_char s2_init[] = {static_cast<odd_char>(0x83), static_cast<odd_char>(0x12), static_cast<odd_char>(0)};
    odd_string s2(s2_init);

    assert(s.find_first_of(s2) == 2);
    assert(s2.find_first_of(s) == 0);

    assert(s.find_last_of(s2) == 3);
    assert(s2.find_last_of(s) == 1);

    return 0;
}
C:\Users\ALEXG~1\AppData\Local\Temp>cl /Od /MDd repro.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.42.34226.3 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

repro.cpp
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\__msvc_string_view.hpp(664): error C2338: static_assert failed: 'Standard char_traits is only provided for char, wchar_t, char16_t, and char32_t. See N4950 [char.traits]. Visual C++ accepts other unsigned integral types as an extension.'
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\__msvc_string_view.hpp(664): note: the template instantiation context (the oldest one first) is
repro.cpp(107): note: see reference to class template instantiation 'std::basic_string<odd_char,std::char_traits<odd_char>,std::allocator<odd_char>>' being compiled
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\xstring(2693): note: while compiling class template member function 'unsigned __int64 std::basic_string<odd_char,std::char_traits<odd_char>,std::allocator<odd_char>>::find_last_of(const std::basic_string<odd_char,std::char_traits<odd_char>,std::allocator<odd_char>> &,unsigned __int64) noexcept const'
repro.cpp(119): note: see the first reference to 'std::basic_string<odd_char,std::char_traits<odd_char>,std::allocator<odd_char>>::find_last_of' in 'main'
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\xstring(2695): note: see reference to function template instantiation 'size_t std::_Traits_find_last_of<_Traits,true>(const odd_char *const ,const size_t,const size_t,const odd_char *const ,const size_t) noexcept' being compiled
        with
        [
            _Traits=std::char_traits<odd_char>
        ]
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\__msvc_string_view.hpp(730): note: see reference to class template instantiation 'std::_String_bitmap<std::char_traits<odd_char>::char_type,false>' being compiled

Expected behavior

Should compile

STL version

Version 17.12.0 Preview 1.0

@AlexGuteniev AlexGuteniev changed the title <string>: basic_string<unicorn>::find_meow_of family with std::string_traits<unicorn> specialization are not supported <string>: basic_string<unicorn>::find_meow_of family with std::char_traits<unicorn> specialization are not supported Sep 3, 2024
@CaseyCarter CaseyCarter added the bug Something isn't working label Sep 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants