3

This is my test code:

#include<vector> #include<iostream> #include<type_traits> using std::vector; using std::is_same_v; using std::cout; using std::endl; int func() { struct data { int i; char c; }; vector<data> vD1; vD1.push_back(data()); vD1.at(0).i = 0; vD1.at(0).c = 'a'; auto iter = vD1.begin(); vector<decltype(*iter)>vD2; if(is_same_v<decltype(vD1),decltype(vD2)>) { cout << "similar types" << endl; } else { cout << "dissimilar types" << endl; } return 0; } int main() { auto exit = (int (*)()) &func; std::cout << exit() << std::endl; } 

The code fails to compile with the following error:

g++ -c -o code.o code.cpp -ggdb -g3 -pedantic-errors -Wall -Wextra -Wfatal-errors -Wpedantic -std=c++20 In file included from /usr/include/c++/11/x86_64-redhat-linux/bits/c++allocator.h:33, from /usr/include/c++/11/bits/allocator.h:46, from /usr/include/c++/11/vector:64, from code.cpp:1: /usr/include/c++/11/ext/new_allocator.h: In instantiation of ‘class __gnu_cxx::new_allocator<func()::data&>’: /usr/include/c++/11/bits/allocator.h:124:11: required from ‘class std::allocator<func()::data&>’ /usr/include/c++/11/bits/stl_vector.h:87:21: required from ‘struct std::_Vector_base<func()::data&, std::allocator<func()::data&> >’ /usr/include/c++/11/bits/stl_vector.h:389:11: required from ‘class std::vector<func()::data&>’ code.cpp:25:26: required from here /usr/include/c++/11/ext/new_allocator.h:103:7: error: forming pointer to reference type ‘func()::data&’ 103 | allocate(size_type __n, const void* = static_cast<const void*>(0)) | ^~~~~~~~ compilation terminated due to -Wfatal-errors. 

I am positive that the error stems from my usage of decltype to specify the type of the second vector VD2. Why does the usage result in the error, since *iter should yield me an object whose type is data?

Secondly, I am certainly more puzzled by the error reported by the compiler; just reading the report doesn't help me understand what the error is that the compiler is trying to convey.

Look forward to some clarification.

3
  • 1
    Oftentimes clang is a bit more helpful in error messages than gcc. Here it mentions that you're trying to instantiate vector<data&> relatively early on: <source>:25:26: note: in instantiation of template class 'std::vector<data &>' requested here 25 | vector<decltype(*iter)>vD2; godbolt.org/z/rPrKEnahf Commented Jul 11 at 10:56
  • std::vector<std::remove_cvref_t<decltype(*iter)>> Commented Jul 11 at 12:20
  • 1
    You are trying to create a vector of references *iter is a `func&" (not a func) and MSVC is really clear about this : static_assert failed: The C++ Standard forbids allocators for reference elements because of [allocator.requirements].. Commented Jul 11 at 12:55

2 Answers 2

4

I am positive that the error stems from my usage of decltype to specify the type of the second vector VD2 [...]

Yes, you are right about this. The decltype(*iter) yields a reference type (data&). Vectors must store objects, not references. So vector<decltype(*iter)> becomes vector<data&>. But std::vector<data&> is illegal because: std::allocator<data&> tries to create data&* (a pointer to a reference), which is invalid C++.

The compiler error "forming pointer to reference type ‘func()::data&’" is explaining exactly that—you can’t have pointers to references—hence the allocator fails to compile.

That’s why you're seeing the error deep inside the instantiation of vector<...>.


How to fix it?

If you want a vector of copies of the objects, use the unqualified object type:

using value_type = std::decay_t<decltype(*iter)>; // strips reference and cv-qualifiers std::vector<value_type> vD2; 

Or more idiomatically:

std::vector<typename std::vector<data>::value_type> vD2; 

This yields vector, which is valid.

If you intentionally want to store references (very rare), you’d need std::reference_wrapper<data>:

std::vector<std::reference_wrapper<data>> vD2; // With `#include <functional>` 
Sign up to request clarification or add additional context in comments.

Comments

2

decltype(*iter) is data& and you cannot make a vector of references.

you want to use std::decay_t to remove the const/ref/volatile qualifications of the type.

vector<std::decay_t<decltype(*iter)>> vD2; 

online demo

If you want a vector of references then you need std::reference_wrapper as the element type.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.