4
template <typename T>
class MyPointer
{public:


    template <typename U>
    void operator=(MyPointer<U>&& other)
    {
      
    }
    char* get() const { return pointer; }
private:
    char* pointer;
};

int main()
{
    struct B {};
    struct D : B{};   

    MyPointer<B> my_pointer_b;
    MyPointer<D> my_pointer_d;

    my_pointer_b = my_pointer_d;


}

The error I get:

binary '=': no operator found which takes a right-hand operand of type 'MyPointermain::D' (or there is no acceptable conversion)

The compiler instantiates the assignment operator for the particular type that I use, so even if it deleted the default one the instantiated one should be there.

3
  • @Yksisarvinen No it doesn't && is a universal reference, not an r-value. It takes both Commented Jul 6, 2023 at 12:57
  • 4
    U&& would be universal ref, C<U>&& is not. Commented Jul 6, 2023 at 12:58
  • @Yksisarvinen ohhhhh, that's not a universal reference, i would have been if it was U type Commented Jul 6, 2023 at 12:58

2 Answers 2

6

Perhaps the error with gcc helps to shed more light on this:

<source>:24:20: error: cannot bind rvalue reference of type 'MyPointer<main()::D>&&' to lvalue of type 'MyPointer<main()::D>'
   24 |     my_pointer_b = my_pointer_d;
      |                    ^~~~~~~~~~~~

Your MyPointer<U>&& is not a forwarding reference. Its a rvalue reference.

From cppreference:

Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of std::forward. Forwarding references are either:

  1. function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template:
  2. [... auto&& ...]

This is a forwarding reference

template <typename T> void foo(T&&);

This one is not

template <typename T> void bar(X<T>&&);
Sign up to request clarification or add additional context in comments.

Comments

5
template <typename U>
void operator=(MyPointer<U>&& other)

In this, MyPointer<U>&& is not a forwarding reference. It's an rvalue reference to some MyPointer<U>, where U is deduced from the argument.

As a result, you cannot call this function with an lvalue.

If you want to use a forwarding reference but constrain it to a MyPointer instance, then you can do something like this:

// forward declaration
template <typename T>
class MyPointer;

template <typename T>
struct IsMyPointerInstance : std::false_type {};

template <typename T>
struct IsMyPointerInstance<MyPointer<T>> : std::true_type {};

template <typename T>
concept MyPointerInstance = IsMyPointerInstance<std::remove_cvref_t<T>>::value;

template <typename T>
class MyPointer {
public:
    template <typename U> requires MyPointerInstance<U>
    void operator=(U&& other) {
        // ...
    }

Demo

(or use SFINAE if you can't use concepts)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.