Reputation: 889
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. 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. The following code reproduces the errors:
(Note that the code does not make much sense as it is.)
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;
}
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(i.e. error C2039: '_Alloc': is not a member of 'std::allocator<char>'
) originates from the 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.
2- Replacing 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));
seems to fix the problem.
I appreciate any ideas on why this is happening.
Upvotes: 3
Views: 1930
Reputation: 137414
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. In your code, it's std::_Vb_reference<std::allocator<char>>
.
Just...don't do it.
Upvotes: 3