c++ - 在头文件中包含 std::vector 会导致模板实例化错误

标签 c++ templates vector

直到今天,我有一个代码在 Visual Studio 2017 中编译得很好,但现在我不断收到来自 std::vector 的模板实例化错误。在帖子末尾提供。我应该补充一点,从那时(当代码编译正常时)到现在,没有一行代码被更改。

当我隔离问题时,它奇怪地归结为是否 std::vector包含在其中一个头文件中。以下代码重现错误:
(请注意,代码并没有多大意义。)


CDataUnit_ALB.h:

#pragma once

#include "DataUnit\CDataUnit.h"

// #include <vector> // <== UnREM'ing this results in compile errors

class CDataUnit_ALB :
    public CDataUnit
{
public:
    friend
    void swap(CDataUnit_ALB& lhs, CDataUnit_ALB& rhs) {
        using Base_t = CDataUnit;

        using std::swap;
        swap(static_cast<Base_t&>(lhs), static_cast<Base_t&>(rhs));
    }
};

CDataUnit.h

#pragma once

#include <memory>

template<typename Tp_Alloc = std::allocator<char>>
class basic_CDataUnit
{
public:
    using allocator_type = 
        typename std::allocator_traits<Tp_Alloc>::template rebind_alloc<char>;

    struct Representation :
        public allocator_type
    {
        char* data;

        friend
        void swap(Representation& lhs, Representation& rhs) noexcept {
            using std::swap;
            swap<allocator_type>(lhs, rhs); // swap base members
            swap(lhs.data, rhs.data);
        }
    };

    Representation m_r;

    friend
    void swap(basic_CDataUnit& lhs, basic_CDataUnit& rhs) noexcept {
        using std::swap;
        swap(lhs.m_r, rhs.m_r);
    }
};

using CDataUnit = basic_CDataUnit<>;

主要.cpp

#include "DataUnit\CDataUnit_ALB.h"

int main() {
    return 0;
}

这是我遇到的编译错误:

1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>CDataUnit_ALB.cpp
1>c:\[path_to_msvc]\14.11.25503\include\vector(2131): error C2039: '_Alloc': is not a member of 'std::allocator<char>'
1>c:\[path_to_msvc]\14.11.25503\include\iosfwd(628): note: see declaration of 'std::allocator<char>'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2179): note: see reference to class template instantiation 'std::_Vb_iter_base<_Alvbase_wrapped>' being compiled
1>        with
1>        [
1>            _Alvbase_wrapped=std::allocator<char>
1>        ]
1>c:\[path_to_project]\cdataunit.h(20): note: see reference to class template instantiation 'std::_Vb_reference<std::allocator<char>>' being compiled
1>c:\[path_to_project]\cdataunit.h(18): note: while compiling class template member function 'void swap(basic_CDataUnit<std::allocator<char>>::Representation &,basic_CDataUnit<std::allocator<char>>::Representation &) noexcept'
1>c:\[path_to_project]\cdataunit.h(25): note: see reference to class template instantiation 'basic_CDataUnit<std::allocator<char>>::Representation' being compiled
1>c:\[path_to_project]\cdataunit_alb.h(10): note: see reference to class template instantiation 'basic_CDataUnit<std::allocator<char>>' being compiled
1>c:\[path_to_msvc]\14.11.25503\include\vector(2131): error C2061: syntax error: identifier '_Alloc'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2131): error C2238: unexpected token(s) preceding ';'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2132): error C2065: '_Alvbase': undeclared identifier
1>c:\[path_to_msvc]\14.11.25503\include\vector(2132): error C2923: 'std::allocator_traits': '_Alvbase' is not a valid template type argument for parameter '_Alloc'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2132): error C2955: 'std::allocator_traits': use of class template requires template argument list
1>c:\[path_to_msvc]\14.11.25503\include\xmemory0(878): note: see declaration of 'std::allocator_traits'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2132): error C2039: 'size_type': is not a member of 'std::allocator_traits<_Alloc>'
1>c:\[path_to_msvc]\14.11.25503\include\xmemory0(196): note: see declaration of 'std::allocator_traits<_Alloc>'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2132): error C2061: syntax error: identifier 'size_type'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2132): error C2238: unexpected token(s) preceding ';'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2133): error C2065: '_Alvbase': undeclared identifier
1>c:\[path_to_msvc]\14.11.25503\include\vector(2133): error C2923: 'std::allocator_traits': '_Alvbase' is not a valid template type argument for parameter '_Alloc'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2133): error C2955: 'std::allocator_traits': use of class template requires template argument list
1>c:\[path_to_msvc]\14.11.25503\include\xmemory0(878): note: see declaration of 'std::allocator_traits'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2133): error C2039: 'difference_type': is not a member of 'std::allocator_traits<_Alloc>'
1>c:\[path_to_msvc]\14.11.25503\include\xmemory0(196): note: see declaration of 'std::allocator_traits<_Alloc>'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2133): error C2061: syntax error: identifier 'difference_type'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2133): error C2238: unexpected token(s) preceding ';'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2134): error C2065: '_Alvbase': undeclared identifier
1>c:\[path_to_msvc]\14.11.25503\include\vector(2134): error C2923: 'std::_Rebind_alloc_t': '_Alvbase' is not a valid template type argument for parameter '_Alloc'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2141): error C2061: syntax error: identifier '_Sizet'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2148): error C2061: syntax error: identifier '_Sizet'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2155): error C2061: syntax error: identifier '_Sizet'
1>c:\[path_to_msvc]\14.11.25503\include\vector(2172): error C3646: '_Myoff': unknown override specifier
1>c:\[path_to_msvc]\14.11.25503\include\vector(2172): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

奇怪的观察:

1- 第一个错误(即 error C2039: '_Alloc': is not a member of 'std::allocator<char>' )源自 typedef using _Alvbase = typename _Alvbase_wrapped::_Alloc;在类里面_Vb_iter_base这似乎与 bool 有关特化std::vector并且代码中的任何地方都没有使用这种特化。

2- 替换 swap<allocator_type>(lhs, rhs);friend void swap(Representation& lhs, Representation& rhs)在 CDataUnit.h 中使用 swap(static_cast<allocator_type&>(lhs), static_cast<allocator_type&>(rhs));似乎解决了这个问题。

我很感激任何关于为什么会发生这种情况的想法。

最佳答案

考虑一下:

template<class T> struct foo : T { };
template<class T> void swap(foo<T>, foo<T>);
template<class T> void swap(T&, T&);

int i = 1, j = 2;
swap<int>(i, j);

你认为会发生什么?

main.cpp:1:36: error: base specifier must name a class
    template<class T> struct foo : T { };
                                   ^
main.cpp:6:15: note: in instantiation of template class 'foo<int>' requested here
    swap<int>(i, j);
              ^

因为您指定了一个显式模板参数,所以它被替换到重载集中每个函数模板的签名中,这意味着如果类模板,您可以使用它们永远不会使用的类型来实例化类模板用于其中一个重载的签名。

在上面的示例中,该替换触发了 foo<int> 的实例化,这会触发一个硬错误。在您的代码中,它是 std::_Vb_reference<std::allocator<char>> .

只是...不要这样做。

关于c++ - 在头文件中包含 std::vector 会导致模板实例化错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47307748/

相关文章:

c++ - 是否需要对具有格式错误的默认模板参数的未使用成员模板进行诊断?

c++ - 在其赋值运算符方法中调用对象的析构函数

c++ - SFML Vector2 用法

c++ - 如何为 std::array 中的 std::vectors 保留内存?

C++类对象内存映射

c++ - 将整数或字符转换为相应的枚举

c++ - 从一组有限的类静态转换为一个类

c++ - 如何预先计算值数组?

c++ - Qt 添加 Widget 到 GraphicsView?

c++ - 'std::vector' : 'U64' is not a valid template type argument for parameter '_Ty'