c++compiler-errorsc++17stdvectordecltype

How to instantiate std::vector using decltype?


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.


Solution

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