njgrout
njgrout

Reputation: 21

Template universal reference in c++ does not compile

I'm having trouble understanding why my code doesn't compile here. I'm getting a lot of error messages from the standard library, along the lines of

main3.cpp:10:20:   required from ‘void addAndCout(T&&) [with T = const char (&)[11]]’
main3.cpp:20:28:   required from here
/usr/include/c++/5/bits/alloc_traits.h:450:27: error: forming pointer to reference type ‘const char (&)[11]’
       using pointer = _Tp*;
                           ^
/usr/include/c++/5/bits/alloc_traits.h:453:39: error: forming pointer to reference type ‘const char (&)[11]’
       using const_pointer = const _Tp*;

This doesn't make sense to me since I thought T&&, when T has not been deduced, is a universal reference, which should be able to bind to an rvalue or lvalue. This example posted is me trying to copy a section from Scott Meyer's "Effective Modern C++" where I was reading about universal references. Photo of example from the book

I'm just wondering why this won't compile or what I'm missing here, since as far as I can tell it's effectively the same to the example.

#include <iostream>
#include <vector>
#include <string>
using std::cout;
using std::endl;

template<typename T>
void addAndCout(T &&name)
{
    std::vector<T> v;

    cout << name << endl;
    v.emplace_back(std::forward<T>(name));
}

int main(int argc, char **argv)
{
    std::string name {"test"};

    addAndCout(std::string("rvalue")); // FINE      move rvalue instead of copying it
    addAndCout("New string");          // ERROR     make a new string instead of copying
    addAndCout(name);                  // ERROR     copy lvalue
}

Upvotes: 2

Views: 454

Answers (2)

Temple
Temple

Reputation: 1631

  • When you do addAndCout(std::string("rvalue")); this is rvalue reference and template parameter T is std::string and this::std::vector<std::string> v; which is valid.
  • But when you do addAndCout("New string"); T is deduced as reference to array of const char, and you can't have vector of references
  • And when you do addAndCout(name); you are passing l-value ref, and T becomes std::string& and similar you can't have vectors of references.

Upvotes: 1

M.M
M.M

Reputation: 141544

There cannot be a vector of references, nor a vector of C-style arrays. The line std::vector<T> v; fails to compile when the argument is an lvalue and/or a C-style array.

Your code differs from the book in that you do std::vector<T> v; whereas the book does not.

To support the usage addAndCout(name); you could change the vector definition to:

std::vector< typename std::remove_cv<typename std::remove_reference<T>::type>::type > v;

(the remove_cv is because there cannot be a vector of const objects either).

To support the C-style array it would be simplest to add an extra overload:

template<typename T, size_t N>
void addAndCout(T (&name)[N])
{
     // do whatever...
}

Upvotes: 3

Related Questions