首页 > 解决方案 > 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, std::char_traits<char>,
        STLAdaptor<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, std::char_traits<char>, STLAdaptor<char, CustomAllocator> >::basic_istringstream(std::__cxx11::basic_string<char, std::char_traits<char>, STLAdaptor<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, _Traits, _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, _Traits, _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, _Traits, _Alloc>::__string_type = std::__cxx11::basic_string<char, std::char_traits<char>, STLAdaptor<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, _Traits, _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, _Traits, _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存在,这肯定解释了我的错误。

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

标签: c++memory-managementc++20stringstreamallocator

解决方案


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

在 C++20 正式标准化之前,您可以使用 10.2 之后的 gcc 主干,它支持 C++20 构造函数,因此编译代码没有错误:

现场神螺栓示例


推荐阅读