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

时间:2017-11-15 12:43:25

标签: 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<>;

的main.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>')来自类using _Alvbase = typename _Alvbase_wrapped::_Alloc;中的typedef _Vb_iter_base,它似乎与bool std::vector的特化有关。 1}}并且代码中的任何地方都不使用该特化。

2-用swap<allocator_type>(lhs, rhs);替换CDataUnit.h中friend void swap(Representation& lhs, Representation& rhs)中的swap(static_cast<allocator_type&>(lhs), static_cast<allocator_type&>(rhs));似乎可以解决问题。

我很感激为什么会发生这种情况。

1 个答案:

答案 0 :(得分:2)

考虑一下:

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>>

只是......不要这样做。