简体   繁体   English

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

[英]Including std::vector in header file results in template instantiation errors

I have a code that compiled just fine in Visual Studio 2017 until today, but now I keep getting template instantiation errors from std::vector which are provided at the end of the post. 我有一个代码在Visual Studio 2017中编译得很好,直到今天,但现在我不断从std::vector获取模板实例化错误,这些错误在帖子的末尾提供。 I should add that not a single line of code has been changed between then(when code compiled ok) and now. 我应该补充说,在那之间(代码编译好)和现在之间没有改变任何一行代码。

When I isolated the problem, it strangely boiled down to whether or not std::vector is included in one of the header files. 当我分离出这个问题时,奇怪地归结为std::vector是否包含在其中一个头文件中。 The following code reproduces the errors: 以下代码重现错误:
(Note that the code does not make much sense as it is.) (请注意,代码没有多大意义。)


CDataUnit_ALB.h: 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 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 main.cpp中

#include "DataUnit\CDataUnit_ALB.h"

int main() {
    return 0;
}

Here is the compile errors I am getting: 这是我得到的编译错误:

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

Strange Observations: 奇怪的观察:

1- The first error(ie error C2039: '_Alloc': is not a member of 'std::allocator<char>' ) originates from the typedef using _Alvbase = typename _Alvbase_wrapped::_Alloc; 1-第一个错误(即error C2039: '_Alloc': is not a member of 'std::allocator<char>' )来自using _Alvbase = typename _Alvbase_wrapped::_Alloc;的typedef using _Alvbase = typename _Alvbase_wrapped::_Alloc; in class _Vb_iter_base which, it seems, has to do with bool specialization of std::vector and that specialization is not used anywhere in the code. 在类_Vb_iter_base中,它似乎与std::vector bool有关,并且在代码中的任何地方都不使用特化。

2- Replacing swap<allocator_type>(lhs, rhs); 2-替换swap<allocator_type>(lhs, rhs); in friend void swap(Representation& lhs, Representation& rhs) in CDataUnit.h with swap(static_cast<allocator_type&>(lhs), static_cast<allocator_type&>(rhs)); in friend void swap(Representation& lhs, Representation& rhs) in CDataUnit.h with swap(static_cast<allocator_type&>(lhs), static_cast<allocator_type&>(rhs)); seems to fix the problem. 似乎解决了这个问题。

I appreciate any ideas on why this is happening. 我很感激为什么会发生这种情况。

Consider this: 考虑一下:

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

What do you think happens? 你觉得怎么样?

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);
              ^

Because you specified an explicit template argument, it's substituted into the signature of every function template in the overload set, which means that you can cause the instantiation of class templates with types they are never meant to be used with if the class template is used in the signature of one of the overloads. 因为您指定了一个显式模板参数,所以它被替换为重载集中每个函数模板的签名,这意味着如果使用类模板,您可以使用它们从未打算使用的类型来实例化类模板。其中一个重载的签名。

In the above example, that substitution triggers the instantiation of foo<int> , which triggers a hard error. 在上面的示例中,该替换触发了foo<int>的实例化,这会触发硬错误。 In your code, it's std::_Vb_reference<std::allocator<char>> . 在你的代码中,它是std::_Vb_reference<std::allocator<char>>

Just...don't do it. 只是......不要这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM