0

我有一个包装 Win32 API 函数的类方法WriteFile()。此 API 函数接受LPCVOID要写入的数据的参数。但相反,我想将 C++ 迭代器传递给它。我该怎么做?


WriteFile()功能:

BOOL WINAPI WriteFile(
  _In_         HANDLE hFile,
  _In_         LPCVOID lpBuffer,
  _In_         DWORD nNumberOfBytesToWrite,
  _Out_opt_    LPDWORD lpNumberOfBytesWritten,
  _Inout_opt_  LPOVERLAPPED lpOverlapped
);

我的实现:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfBytesWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    if (m_nFileState != STATE_OPEN) return WRITE_FILE_NOT_OPEN;
    BOOL bResult = WriteFile((HANDLE)       m_hFile,
                            (LPCVOID)       Begin,
                            (DWORD)         sizeof(*Begin) * (End - Begin),
                            (LPDWORD)       &dwNumberOfBytesWritten,
                            (LPOVERLAPPED)  NULL);
    m_dwLastError = ::GetLastError();
    m_FilePointer += dwNumberOfBytesWritten;
    if (bResult)
        return WRITE_SUCCESSFUL;
    else
        return WRITE_FAILURE;
}

尝试调用它:

TextFile::RETURN_VALUES TextFile::Write(std::vector<uint8_t> & String)
{
    DWORD dwNumberOfBytesWritten;
    BinaryFile::RETURN_VALUES WriteReturn = m_File.Write(
                            String.begin(),
                            String.end(),
                            dwNumberOfBytesWritten);
    if (WriteReturn == BinaryFile::RETURN_VALUES::WRITE_SUCCESSFUL)
        return WRITE_SUCCESSFUL;
    else if (dwNumberOfBytesWritten < String.end() - String.begin())
        return WRITE_NOT_ALL_WRITTEN;
    else
        return WRITE_FAILURE;
}

我得到的编译器(VS2012)错误:

BinaryFile.h
错误 C2440
'type cast':无法从 'std::_Vector_iterator<_Myvec>' 转换为 'LPCVOID'

4

2 回答 2

3

对于像std:::vector<some POD type>or这样的简单容器std::string,您可以这样做:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfBytesWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    BOOL bResult = WriteFile((HANDLE)       m_hFile,
                            (LPCVOID)       &*Begin,
                            (DWORD)         sizeof(*Begin) * (End - Begin),
                            (LPDWORD)       &dwNumberOfBytesWritten,
                            (LPOVERLAPPED)  NULL);

    m_dwLastError = ::GetLastError();
    if (!bResult)
        return WRITE_FAILURE;

    m_FilePointer += dwNumberOfBytesWritten;
    return WRITE_SUCCESSFUL;
}

但是对于更复杂的容器,例如std::list,您必须改为这样做(这将适用于所有容器,但前提是它们包含 POD 类型):

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfBytesWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    dwNumberOfBytesWritten = 0;

    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    DWORD dwWritten;
    while (Begin != End)
    {
        BOOL bResult = WriteFile((HANDLE)       m_hFile,
                                (LPCVOID)       &*Begin,
                                (DWORD)         sizeof(*Begin),
                                (LPDWORD)       &dwWritten,
                                (LPOVERLAPPED)  NULL);
        m_dwLastError = ::GetLastError();
        if (!bResult)
            return WRITE_FAILURE;

        m_FilePointer += dwWritten;
        dwNumberOfBytesWritten += dwWritten;

        ++Begin;
    }

    return WRITE_SUCCESSFUL;
}

在这种情况下dwNumberOfBytesWritten并没有那么有意义。将其更改为更有意义dwNumberOfItemsWritten,例如:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfItemsWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    dwNumberOfItemsWritten = 0;

    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    DWORD dwWritten;
    while (Begin != End)
    {
        BOOL bResult = WriteFile((HANDLE)       m_hFile,
                                (LPCVOID)       &*Begin,
                                (DWORD)         sizeof(*Begin),
                                (LPDWORD)       &dwWritten,
                                (LPOVERLAPPED)  NULL);
        m_dwLastError = ::GetLastError();
        if (!bResult)
            return WRITE_FAILURE;

        m_FilePointer += dwWritten;
        ++dwNumberOfItemsWritten;

        ++Begin;
    }

    return WRITE_SUCCESSFUL;
}

TextFile::RETURN_VALUES TextFile::Write(std::vector<uint8_t> & String)
{
    DWORD dwNumberOfItemsWritten;
    BinaryFile::RETURN_VALUES WriteReturn = m_File.Write(
                            String.begin(),
                            String.end(),
                            dwNumberOfItemsWritten);
    if (WriteReturn == BinaryFile::RETURN_VALUES::WRITE_SUCCESSFUL)
        return WRITE_SUCCESSFUL;
    else if (dwNumberOfItemsWritten < String.size())
        return WRITE_NOT_ALL_WRITTEN;
    else
        return WRITE_FAILURE;
}

最后,在任何一种情况下,不要忘记WriteFile()不能保证写入你请求的字节数,所以你真的应该在循环中调用它,直到所有预期的数据都被完整写入或直到发生错误,例如:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfItemsWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    dwNumberOfItemsWritten = 0;

    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    DWORD dwWritten;
    while (Begin != End)
    {
        LPBYTE pData = (LPBYTE) &*Begin;
        DWORD dwSize = sizeof(*Begin);

        do
        {
            BOOL bResult = WriteFile((HANDLE)       m_hFile,
                                     (LPCVOID)      pData,
                                     (DWORD)        dwSize,
                                     (LPDWORD)      &dwWritten,
                                     (LPOVERLAPPED) NULL);
            m_dwLastError = ::GetLastError();
            if (!bResult)
                return WRITE_FAILURE;

            m_FilePointer += dwWritten;

            pData += dwWritten;
            dwSize -= dwWritten;
        }
        while (dwSize > 0);

        ++dwNumberOfItemsWritten;
        ++Begin;
    }

    return WRITE_SUCCESSFUL;
}
于 2013-05-17T04:04:40.990 回答
0

您可以(甚至应该)将您的函数专门用于向量的迭代器和原始指针,并拒绝所有其他。对于向量的迭代器,您可以&*Begin像@chris 所说的那样传递给指针样式的函数。我不确定你是否可以调用迭代器,但你可以试试这个技巧operator*End

auto e = End;
e--;
auto pe = &*e;
e++;

最后:您应该Begin != End在函数开始时检查

于 2013-05-17T04:05:55.910 回答