How to utilize template copy&move constructor and assignment operator?
Asked Answered
F

2

5

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>.

Freeload answered 5/1, 2019 at 10:2 Comment(6)
Copy/move constructors are never templates. If you don't want the copy/move constructors to do the work, maybe you can delegate. Show what part of the implementation bothers you; it might be better placed outside of any constructor.Mercaptopurine
A<int> a1(); is a function declaration ("most vexing parse...") also all the constructors are privateSquab
instead of delete regular copy/move constructor/assignment, forward them to template implementation.Eyeopener
@Jarod42, what specifically do you mean by forwarding? It seems this is what I'm asking for - how to forward.Freeload
@SergeRogatch - you can forwarding adding an unused argument (with default value) in template constructorNudicaul
Only defaulted special member function defined as deleted do not participate to overload resolution.Tyronetyrosinase
S
5

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

Squab answered 5/1, 2019 at 10:45 Comment(0)
N
1

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); }
Nudicaul answered 5/1, 2019 at 11:3 Comment(4)
What about operator=? Trying to add a dummy parameter gives compiler errors binary 'operator =' has too many parameters and 'operator =' cannot have default parametersFreeload
@SergeRogatch - answer improved; hope this helps.Nudicaul
@max66: or return operator=<T>(rhs);.Eyeopener
@Eyeopener - You're right: works and it's simpler. Thanks.Nudicaul

© 2022 - 2024 — McMap. All rights reserved.