Skip to main content
Code Review

Return to Question

added 18 characters in body
Source Link
Miklas
  • 378
  • 1
  • 9

I'm writing a templatized container and wanted to use an universal reference for the Add(T&& object) function. Check out isocpp if you need an update on your universal/rvalue references. A quick example from that page states that, since the class is templatized, T&& is fully specified and therefore a rvalue, not an universal reference.

template <class T, class Allocator = allocator<T> >
class vector {
public:
 ...
 void push_back(T&& x); // fully specified parameter type ⇒ no type deduction;
 ... // && ≡ rvalue reference
};

This means that I cannot pass lvalues to the push_back function above.

vector<T> list;
list.Add(T()); // rvalue, compiles fine.
T data;
list.Add(data); // lvalue, does not compile.

In the case of std::vector this is solved by having a push_back(const T& object) overload. However, since the code in my Add function is quite complex, I didn't want to copy it over.

However, if I am to templatize my add function, it does become universal reference. So I came up with the following code.

#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;
template <class T>
class Container
{
 public:
 template <class UR = T>
 void Add(UR&& object)
 {
 static_assert(std::is_same<std::remove_reference_t<UR>remove_cv_t<std::remove_reference_t<UR>>, T>::value, "UR and T should be the same!");
 m_Vector.push_back(std::forward<UR>(object));
 }
 std::vector<T> m_Vector;
};
class Data
{
 public:
 int x;
 int y;
};
int main() {
 Container<Data> list;
 Data d;
 list.Add(d);
 return 0;
}

I've added the static assert to make sure that people do not actually templatize the Add function. Does anyone know a cleaner solution, since this feels a bit of template magic? Should I follow the std method and just copy my add function (which is a bit more complex than this minimal example)? Can anyone come up with a case where my solution will not work?

Here is a small ideone version for you to play around with.

I'm writing a templatized container and wanted to use an universal reference for the Add(T&& object) function. Check out isocpp if you need an update on your universal/rvalue references. A quick example from that page states that, since the class is templatized, T&& is fully specified and therefore a rvalue, not an universal reference.

template <class T, class Allocator = allocator<T> >
class vector {
public:
 ...
 void push_back(T&& x); // fully specified parameter type ⇒ no type deduction;
 ... // && ≡ rvalue reference
};

This means that I cannot pass lvalues to the push_back function above.

vector<T> list;
list.Add(T()); // rvalue, compiles fine.
T data;
list.Add(data); // lvalue, does not compile.

In the case of std::vector this is solved by having a push_back(const T& object) overload. However, since the code in my Add function is quite complex, I didn't want to copy it over.

However, if I am to templatize my add function, it does become universal reference. So I came up with the following code.

#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;
template <class T>
class Container
{
 public:
 template <class UR = T>
 void Add(UR&& object)
 {
 static_assert(std::is_same<std::remove_reference_t<UR>, T>::value, "UR and T should be the same!");
 m_Vector.push_back(std::forward<UR>(object));
 }
 std::vector<T> m_Vector;
};
class Data
{
 public:
 int x;
 int y;
};
int main() {
 Container<Data> list;
 Data d;
 list.Add(d);
 return 0;
}

I've added the static assert to make sure that people do not actually templatize the Add function. Does anyone know a cleaner solution, since this feels a bit of template magic? Should I follow the std method and just copy my add function (which is a bit more complex than this minimal example)? Can anyone come up with a case where my solution will not work?

Here is a small ideone version for you to play around with.

I'm writing a templatized container and wanted to use an universal reference for the Add(T&& object) function. Check out isocpp if you need an update on your universal/rvalue references. A quick example from that page states that, since the class is templatized, T&& is fully specified and therefore a rvalue, not an universal reference.

template <class T, class Allocator = allocator<T> >
class vector {
public:
 ...
 void push_back(T&& x); // fully specified parameter type ⇒ no type deduction;
 ... // && ≡ rvalue reference
};

This means that I cannot pass lvalues to the push_back function above.

vector<T> list;
list.Add(T()); // rvalue, compiles fine.
T data;
list.Add(data); // lvalue, does not compile.

In the case of std::vector this is solved by having a push_back(const T& object) overload. However, since the code in my Add function is quite complex, I didn't want to copy it over.

However, if I am to templatize my add function, it does become universal reference. So I came up with the following code.

#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;
template <class T>
class Container
{
 public:
 template <class UR = T>
 void Add(UR&& object)
 {
 static_assert(std::is_same<std::remove_cv_t<std::remove_reference_t<UR>>, T>::value, "UR and T should be the same!");
 m_Vector.push_back(std::forward<UR>(object));
 }
 std::vector<T> m_Vector;
};
class Data
{
 public:
 int x;
 int y;
};
int main() {
 Container<Data> list;
 Data d;
 list.Add(d);
 return 0;
}

I've added the static assert to make sure that people do not actually templatize the Add function. Does anyone know a cleaner solution, since this feels a bit of template magic? Should I follow the std method and just copy my add function (which is a bit more complex than this minimal example)? Can anyone come up with a case where my solution will not work?

Here is a small ideone version for you to play around with.

edited tags; edited title
Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

universal Universal reference in a class template

Source Link
Miklas
  • 378
  • 1
  • 9

universal reference in a class template

I'm writing a templatized container and wanted to use an universal reference for the Add(T&& object) function. Check out isocpp if you need an update on your universal/rvalue references. A quick example from that page states that, since the class is templatized, T&& is fully specified and therefore a rvalue, not an universal reference.

template <class T, class Allocator = allocator<T> >
class vector {
public:
 ...
 void push_back(T&& x); // fully specified parameter type ⇒ no type deduction;
 ... // && ≡ rvalue reference
};

This means that I cannot pass lvalues to the push_back function above.

vector<T> list;
list.Add(T()); // rvalue, compiles fine.
T data;
list.Add(data); // lvalue, does not compile.

In the case of std::vector this is solved by having a push_back(const T& object) overload. However, since the code in my Add function is quite complex, I didn't want to copy it over.

However, if I am to templatize my add function, it does become universal reference. So I came up with the following code.

#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;
template <class T>
class Container
{
 public:
 template <class UR = T>
 void Add(UR&& object)
 {
 static_assert(std::is_same<std::remove_reference_t<UR>, T>::value, "UR and T should be the same!");
 m_Vector.push_back(std::forward<UR>(object));
 }
 std::vector<T> m_Vector;
};
class Data
{
 public:
 int x;
 int y;
};
int main() {
 Container<Data> list;
 Data d;
 list.Add(d);
 return 0;
}

I've added the static assert to make sure that people do not actually templatize the Add function. Does anyone know a cleaner solution, since this feels a bit of template magic? Should I follow the std method and just copy my add function (which is a bit more complex than this minimal example)? Can anyone come up with a case where my solution will not work?

Here is a small ideone version for you to play around with.

lang-cpp

AltStyle によって変換されたページ (->オリジナル) /