GCC 10.2中是否缺少std :: basic_istringstream的构造函数,如果是的话,如何使用自定义分配器构造一个?

问题描述

我有以下代码

#include <cstdint>
#include <cstdlib>
#include <memory>
#include <string>
#include <sstream>

class CustomAllocator
{
public:
    CustomAllocator(const std::size_t sizeBytes,void* const start)
    :
        m_sizeBytes(sizeBytes),m_usedBytes(0),m_start(start),m_current(start)
    {

    }

    void* Allocate(const std::size_t& numBytes,const std::uintptr_t& alignment)
    {
        std::size_t space = m_sizeBytes - m_usedBytes;
        if(std::align(alignment,numBytes,m_current,space))
        {
            // the amount used for alignment
            m_usedBytes += (m_sizeBytes-m_usedBytes) - space;
            // the amount actually needed
            m_usedBytes += numBytes;

            void* address = m_current;

            m_current = reinterpret_cast<void*>(
                reinterpret_cast<std::uintptr_t>(m_current) + numBytes);

            return address;
        }
        throw std::bad_alloc();
    }

    void Free(void* const ptr)
    {
        // do nothing in this Allocator,but other derived types may
    }

    void Clear()
    {
        m_current = m_start;
        m_usedBytes = 0;
    }

    std::size_t GetSize() const { return m_sizeBytes; }

    void* const GetStart() const { return m_start; }

protected:
    const std::size_t m_sizeBytes;
    std::size_t m_usedBytes;
    void* const m_start;
    void* m_current;
};
// many types derive from base CustomAllocator type

// allows for my custom allocators to be used in STL containers
template<typename T,typename Alloc>
class STLAdaptor
{
public:

    typedef T value_type;

    template<typename U>
    struct rebind
    {
        typedef STLAdaptor<U,Alloc> other;
    };

    STLAdaptor(Alloc& allocator)
    :
        m_allocator(allocator)
    {

    }

    template<typename U>
    STLAdaptor(const STLAdaptor<U,Alloc>& other) noexcept
    :
        m_allocator(other.m_allocator)
    {}

    [[nodiscard]] constexpr T* allocate(std::size_t n)
    {
        return reinterpret_cast<T*>
            (m_allocator.Allocate(n * sizeof(T),alignof(T)));
    }

    constexpr void deallocate(T* p,std::size_t n)
    {
        m_allocator.Free(p);
    }

    std::size_t MaxAllocationSize() const
    {
        return m_allocator.GetSize();
    }

    bool operator==(const STLAdaptor<T,Alloc>& rhs)
    {
        return m_allocator.GetStart() == rhs.m_allocator.GetStart();
    }

    bool operator!=(const STLAdaptor<T,Alloc>& rhs)
    {
        return !(*this == rhs);
    }

    Alloc& m_allocator;
};

int main()
{
    const std::size_t memSize = 10000000;
    void* mem = std::malloc(memSize);

    CustomAllocator customAlloc(memSize,mem);

    std::basic_string<char,std::char_traits<char>,STLAdaptor<char,CustomAllocator>>
        myString(customAlloc);

    myString = "something something";

    std::basic_istringstream<char,CustomAllocator>>
        iss(myString,std::ios_base::in,customAlloc);

    std::free(mem);

    return 0;
}

使用GCC 10.2 -Wall -fexceptions -std=c++2a -g进行编译时,出现以下错误

||=== Build: Debug in CPPTESTS (compiler: Mingw-8.1.0 32bit) ===|
C:\CPPTESTS\main.cpp||In function 'int main()':|
C:\CPPTESTS\main.cpp|136|error: no matching function for call to 'std::__cxx11::basic_istringstream<char,CustomAllocator> >::basic_istringstream(std::__cxx11::basic_string<char,CustomAllocator> >&,const openmode&,CustomAllocator&)'|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|477|note: candidate: 'std::__cxx11::basic_istringstream<_CharT,_Traits,_Alloc>::basic_istringstream(std::__cxx11::basic_istringstream<_CharT,_Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = STLAdaptor<char,CustomAllocator>]'|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|477|note:   candidate expects 1 argument,3 provided|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|460|note: candidate: 'std::__cxx11::basic_istringstream<_CharT,_Alloc>::basic_istringstream(const __string_type&,std::ios_base::openmode) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = STLAdaptor<char,CustomAllocator>; std::__cxx11::basic_istringstream<_CharT,_Alloc>::__string_type = std::__cxx11::basic_string<char,CustomAllocator> >; std::ios_base::openmode = std::ios_base::openmode]'|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|460|note:   candidate expects 2 arguments,3 provided|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|442|note: candidate: 'std::__cxx11::basic_istringstream<_CharT,_Alloc>::basic_istringstream(std::ios_base::openmode) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = STLAdaptor<char,CustomAllocator>; std::ios_base::openmode = std::ios_base::openmode]'|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|442|note:   candidate expects 1 argument,3 provided|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|425|note: candidate: 'std::__cxx11::basic_istringstream<_CharT,_Alloc>::basic_istringstream() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = STLAdaptor<char,CustomAllocator>]'|
C:\MSYS2-32\mingw32\include\c++\10.2.0\sstream|425|note:   candidate expects 0 arguments,3 provided|
||=== Build Failed: 1 error(s),0 warning(s) (0 minute(s),1 second(s)) ===|

看看std::basic_istringstream<sstream>代码,看来https://en.cppreference.com/w/cpp/io/basic_istringstream/basic_istringstream中的构造函数5到9不存在,这肯定解释了我的错误

但是如果是这样,我到底该如何使用有状态的自定义分配器构造这样的对象?

解决方法

似乎gcc 10.2版本不支持std::basic_istringstream的C ++ 20构造函数。

在C ++ 20正式标准化之前,您可以在10.2之后使用gcc干线,该干线支持C ++ 20构造函数,因此可以正确编译代码:

Live godbolt example