How to utilize template copy&move constructor and assignment operator? - c++

Consider the following C++ code with my failed attempt to avoid preference of non-template copy&move constructors and assignment operators:
template<typename T> class A {
public:
A() { /* implementation here */ }
// Remove from the overloads the default copy&move constructors and assignment operators
A(const A&) = delete;
A& operator=(const A&) = delete;
A(A&&) = delete;
A& operator=(A&&) = delete;
// I want these to be used e.g. by std::vector
template<typename U> A(const A<U>& fellow) { /* implementation here */ }
template<typename U> A& operator=(const A<U>& fellow) { /* implementation here */ }
template<typename U> A(A<U>&& fellow) { /* implementation here */ }
template<typename U> A& operator=(A<U>&& fellow) { /* implementation here */ }
};
However, I get the following error
attempting to reference a deleted function
when trying to push A items to a vector or simply copy-construct like:
A<int> a1{};
A<int> a2(a1);
UPDATE1: I need template copy&move constructors and assignment operators, because the template argument really just controls some caching, so A<T1> can be safely assigned to A<T2>.

You can make compiler happy by declaring deleted copy constructor / assignment operator with alternative signature which will not cause this overload to be selected but will prevent generation of constructor / assignment operator by compiler:
template<typename T> class A
{ public:
A() { /* implementation here */ }
// Remove from the implicit declaration of the default copy&move constructors and assignment operators
A(A volatile const &) = delete;
A & operator =(A volatile const &) = delete;
// I want these to be used e.g. by std::vector
template<typename U> A(A<U> const & fellow) { /* implementation here */ }
template<typename U> A & operator =(A<U> const & fellow) { /* implementation here */ return *this;}
template<typename U> A(A<U> && fellow) { /* implementation here */ }
template<typename U> A & operator =(A<U> && fellow) { /* implementation here */ return *this; }
};
int main()
{
A<int> a1{};
A<int> a2{a1};
return 0;
}
online compiler
15.8.1 Copy/move constructors [class.copy.ctor]
1. A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments

A minimal example of a copy constructor that delegate the execution to the template constructor using a second unused (and defaulted) argument
#include <iostream>
template <typename T>
struct A
{
A()
{ }
A (A const & a0) : A{a0, 0}
{ }
template<typename U>
A (A<U> const &, int = 0)
{ std::cout << "template constructor" << std::endl; }
};
int main()
{
A<int> a0;
A<int> a1{a0};
}
-- EDIT --
The OP asks
What about operator=? Trying to add a dummy parameter gives compiler errors binary 'operator =' has too many parameters and 'operator =' cannot have default parameters
For operator=() I propose to "delegate" (not in the meaning of delegating constructor, in this case) both operators to a normal method; a template one.
Something as
template <typename U>
A & assign (A<U> const &)
{ /* do assignment */ return *this; }
A & operator= (A const & a0)
{ return assign(a0); }
template <typename U>
A & operator= (A<U> const & a0)
{ return assign(a0); }
Maybe the assign() method can be a private one.
Or better, as suggested by Jarod42 (thanks), directly calling the template operator from the not-template one
template <typename U>
A & operator= (A<U> const & a0)
{ /* do assignment */ return *this; }
A & operator= (A const & a0)
{ return operator=<T>(a0); }

Related

How to implement copy constructor and assignment operator in a templatic container class?

I have no idea how to cast an int to a double in a copy constructor or either in a assignment constructor.
Is it possible? How to do it?
template <typename T>
class Container {
public:
Container() { //... }
Container(const Container& y) { //... }
Container& operator=(const Container& y) { //... }
~Container() { //... }
private:
// ...
};
int main() {
Container<int> ci;
Container<double> cd;
ci = cd;
}
no match for 'operator=' (operand types are 'Container<double>' and 'Container<int>')
candidate: Container<T>& Container<T>::operator=(const Container<T>&) [with T = double]
For your Container template all instances of plain Container inside the class definition is equal to Container<T>. So for a template argument of int then all Container is equal to Container<int>. And that means your operator= overload only takes a Container<int> argument. The assignment operator declaration you have is equal to
Container<T>& operator=(const Container<T>& y);
Which for an int template argument would be
Container<int>& operator=(const Container<int>& y);
If you want to be able to accept other types as arguments, you need to make the overloaded operators templates themselves:
template<typename U>
Container& operator=(const Container<U>& y);
// ^^^
// Note use of new template argument here

Calling base class template constructor in C++

I have a template base class which has a constructor for conversion from any other template instantiation of that class, like this:
template <class T>
class FooBase
{
public:
FooBase()
{
}
template <class U>
FooBase(const FooBase<U>& other)
{
std::cout << "FooBase<U>" << std::endl;
}
};
Notice how there is no copy constructor defined.
I then have a derived template class which does have a copy constructor, as well as the constructor used for conversion:
template <class T>
class Foo : public FooBase<T>
{
public:
Foo()
{
}
Foo(const Foo& other) :
FooBase<T>(other)
{
}
template <class U>
Foo(const Foo<U>& other) :
FooBase<T>(other)
{
}
};
Because FooBase doesn't have a copy constructor, this results in FooBase<T>(other) making a call to the compiler-generated copy constructor. Which means if I run this:
int main()
{
Foo<int> a;
Foo<int> b(a);
return 0;
}
The output is nothing, when it should be FooBase<U>.
Of course, I could try to solve the issue by creating a copy constructor in FooBase and using delegating constructors:
FooBase(const FooBase& other)
: FooBase<T>(other)
{
}
But unfortunately that doesn't work, and it would result in a recursive call as the compiler helpfully points out:
warning C4717: 'FooBase<int>::FooBase<int>': recursive on all control paths, function will cause runtime stack overflow
So the only solution would be to duplicate the logic into both constructors.
Is there any way around this that doesn't involve code duplication or a separate initialization function?
You could have a third, private constructor that both the copy constructor and the constructor template delegate to and which contains the actual work:
template <typename T> class FooBase
{
struct Tag{};
template <typename U> // May have U = T
FooBase(Tag, const FooBase<U> & rhs)
{
// actual implementation
}
public:
FooBase(const FooBase & rhs) : FooBase(Tag(), rhs) {}
template <typename U> // Never selects U = T
FooBase(const FooBase<U> & rhs) : FooBase(Tag(), rhs) {}
};

C++ perfect forwarding/proxy of encapsulated member

I have been looking online for a way to do a perfect and efficient redirection (proxy) to a member object. But I can't find any useful resource.
I imagine this is a task than programmers are doing often (sometimes badly), and it could be a good knowledge to know a good, efficient and concise (minimalist) way to do it.
I would like your advice to know if my understanding of move operations is right and if this proxy is correct particularly for copy and move constructor / assignment operators.
To do a perfect forwarding in a move constructor / assignment operator my understanding is that we use std::move if we are sure we pass an lvalue to the encapsulated object, and std::forward otherwise.
Is it correct ?
Here is my code
#include <boost/variant.hpp>
/* ********************************************************************/
// Class
/* ********************************************************************/
template <class... T>
class BoostVariantWrapper {
/* ********************************************************************/
// Private fields
/* ********************************************************************/
boost::variant<T...> variant;
public:
/* ********************************************************************/
// Constructors / Destructors
/* ********************************************************************/
BoostVariantWrapper() {}
BoostVariantWrapper(const BoostVariantWrapper &other) :
BoostVariantWrapper(other.variant)
{}
BoostVariantWrapper(BoostVariantWrapper &other) :
BoostVariantWrapper(other.variant)
{}
BoostVariantWrapper(BoostVariantWrapper &&other) :
BoostVariantWrapper(std::move(other.variant))
{}
template<class TOther>
BoostVariantWrapper(TOther &&other) :
variant(std::forward<TOther>(other))
{}
/* ********************************************************************/
// Public methods
/* ********************************************************************/
template <class U>
U& get() {
return boost::get<U>(variant);
}
template <class Fn>
inline void applyVisitor(Fn&& visitor) {
boost::apply_visitor(std::forward<Fn>(visitor), variant);
}
template <class Fn>
inline void applyVisitor(Fn&& visitor) const {
boost::apply_visitor(std::forward<Fn>(visitor), variant);
}
/* ********************************************************************/
// Operators
/* ********************************************************************/
BoostVariantWrapper& operator=(const BoostVariantWrapper &other) {
return operator=(other.variant);
}
BoostVariantWrapper& operator=(BoostVariantWrapper &other) {
return operator=(other.variant);
}
BoostVariantWrapper& operator=(BoostVariantWrapper &&other) {
return operator=(std::move(other.variant));
}
template<class TOther>
BoostVariantWrapper& operator=(TOther &&other) {
variant = std::forward<TOther>(other);
return *this;
}
bool operator==(const BoostVariantWrapper &other) const {
return variant == other.variant;
}
bool operator<(const BoostVariantWrapper &other) const {
return variant < other.variant;
}
friend std::ostream& operator<<(std::ostream &os, const BoostVariantWrapper &x) {
os << x.variant;
return os;
}
/* ********************************************************************/
// Serialization
/* ********************************************************************/
template<class Archive>
void serialize(Archive &ar, const unsigned int) {
ar & variant;
}
};
Edited based on comment of Jarod42
std::forward by itself does perfect forwarding. It is meant for this purpose.

C++ noexcept unknown member function

#include<iostream>
#include<utility>
using namespace std;
struct A
{
void set(const int &){}
void set(int &&) noexcept
{}
};
template<class Assign,class T,class Func>
struct B
{
B& operator=(const Assign &)
{
return *this;
}
B& operator=(Assign &&) noexcept(noexcept(declval<T>().set(declval<Assign>())))
{
return *this;
}
};
int main()
{
cout<<is_nothrow_assignable<B<int,A,void(A::*)(int &&)>&,int&&>::value<<endl;
}
I want to make the line
B& operator=(Assign &&) noexcept(noexcept(declval<T>().set(declval<Assign>())))
to
B& operator=(Assign &&) noexcept(noexcept(declval<T>().Func(declval<Assign>())))
(But it occurs compilation error.)
So that user can specify which member function should be used.
Is there any possible to do that without knowing which member function should be called in advance?
If you use another parameter to specify the function, it'll work.
template<class Assign,class T,class Func, Func f> struct B
//...
B& operator=(Assign &&) noexcept(noexcept((declval<T>().*f)(declval<Assign>())))
//...
cout<<is_nothrow_assignable<B<int,A,void(A::*)(int &&), &A::set>&,int&&>::value<<endl;
Add a Func non-type parameter to B, use member function pointer call syntax in the noexcept operator, and then you can specify the function by passing a pointer to it.
Full code here, if it needs more context.

Can I force a default special member function to be noexcept?

The following structure fails to compile under C++11 due to the fact that I have declared the move assignment operator as noexcept:
struct foo
{
std::vector<int> data;
foo& operator=(foo&&) noexcept = default;
};
The default move assignment operator generated by the compiler is noexcept(false) due to the fact that std::vector<int>'s move assignment is also noexcept(false). This in turn is due to the fact that the default allocator has std::allocator_traits<T>:: propagate_on_container_move_assignment set to std::false_type. See also this question.
I believe this has been fixed in C++14 (see library defect 2103).
My question is, is there a way for me to force noexcept upon the default move assignment assignment operator without having to define it myself?
If this is not possible, is there a way I can trick the std::vector<int> into being noexcept move assignable so that noexcept(true) is passed through to my struct?
I believe this has been fixed in C++14 (see library defect 2103).
As a DR that fix should be considered a correction to C++11 and so some C++11 implementations will have already fixed it.
My question is, is there a way for me to force noexcept upon the default move assignment assignment operator without having to define it myself?
For the defaulted move assignment operator to be noexcept you need to make its sub-objects have noexcept move assignment operators.
The most obvious portable way I can think of is to use a wrapper around std::vector which forces the move to be noexcept
template<typename T, typename A = std::allocator<T>>
struct Vector : std::vector<T, A>
{
using vector::vector;
Vector& operator=(Vector&& v) noexcept
{
static_cast<std::vector<T,A>&>(*this) = std::move(v);
return *this;
}
Vector& operator=(const Vector&) = default;
};
Another similar option is to define your own allocator type with the DR 2013 fix and use that:
template<typename T>
struct Allocator : std::allocator<T>
{
Allocator() = default;
template<typename U> Allocator(const Allocator<U>&) { }
using propagate_on_container_move_assignment = true_type;
template<typename U> struct rebind { using other = Allocator<U>; };
};
template<typename T>
using Vector = std::vector<T, Allocator<T>>;
Another option is to use a standard library implementation such as GCC's which implements the resolution to DR 2013 and also makes std::vector's move assignment operator noexcept for other allocator types when it is known that all allocator instances compare equal.
I do not think you can force anything, but you may wrap it:
#include <iostream>
#include <vector>
template <typename T>
struct Wrap
{
public:
Wrap() noexcept
{
new (m_value) T;
}
Wrap(const Wrap& other) noexcept
{
new (m_value) T(std::move(other.value()));
}
Wrap(Wrap&& other) noexcept
{
std::swap(value(), other.value());
}
Wrap(const T& other) noexcept
{
new (m_value) T(std::move(other));
}
Wrap(T&& other) noexcept
{
new (m_value) T(std::move(other));
}
~Wrap() noexcept
{
value().~T();
}
Wrap& operator = (const Wrap& other) noexcept
{
value() = other.value();
return *this;
}
Wrap& operator = (Wrap&& other) noexcept
{
value() = std::move(other.value());
return *this;
}
Wrap& operator = (const T& other) noexcept
{
value() = other;
return *this;
}
Wrap& operator = (T&& other) noexcept
{
value() = std::move(other);
return *this;
}
T& value() noexcept { return *reinterpret_cast<T*>(m_value); }
const T& value() const noexcept { return *reinterpret_cast<const T*>(m_value); }
operator T& () noexcept { return value(); }
operator const T& () const noexcept { return value(); }
private:
typename std::aligned_storage <sizeof(T), std::alignment_of<T>::value>::type m_value[1];
};
struct Foo
{
public:
Foo& operator = (Foo&&) noexcept = default;
std::vector<int>& data() noexcept { return m_data; }
const std::vector<int>& data() const noexcept { return m_data; }
private:
Wrap<std::vector<int>> m_data;
};
int main() {
Foo foo;
foo.data().push_back(1);
Foo boo;
boo = std::move(foo);
// 01
std::cout << foo.data().size() << boo.data().size() << std::endl;
return 0;
}
(Thanks Jonathan Wakely)