Alexander Sergeyev
Alexander Sergeyev

Reputation: 972

copy constructor as templated member function is ignored

Is it possible for assignment operator to be deduced as a special case of member function template?

For example, I have a class template with one bool parameter and want to implement assign operation regardless any particular value of the template argument.

#include <iostream>

template<bool sw>
struct A {
    A() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }

    template<bool input_sw>
    A & operator = (const A<input_sw> &a) {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        return *this;
    }
};

int main()
{
    A<true> a;
    A<true> b;
    a = b;
}

In the code snippet above clang and gcc-compiled binaries print out nothing about assignment -- as far as I can tell default assignment is generated here despite possibility to deduce it from the template.

Upvotes: 1

Views: 75

Answers (1)

Barry
Barry

Reputation: 302987

It is correct for them to not print anything out. What is happening is that there is an implicit copy assignment operator created for A<true> with this signature:

A<true>& operator=(const A<true>& );

Thus, when we do overload resolution, there are two viable candidates:

A<true>& operator=(const A<true>& );     // implicit copy assignment
A<true>& operator=(const A<input_sw>& ); // [ with input_sw = true ]

Both operators take the same argument (const A<true>&), so they are equivalently good candidates from this perspective. But non template functions are preferred to function template specializations, which makes the implicit copy assignment operator the best viable candidate.


Now, consider an alternative. What if you declared your operator template this way:

template<bool input_sw>
A & operator =(A<input_sw> &a) { ... }

That is, not const. This isn't good practice, and I'm presenting this solely for illustrative purposes. In this case, our two candidates for a=b are:

A<true>& operator=(const A<true>& );   // implicit copy assignment
A<true>& operator=(A<input_sw>& );     // [ with input_sw = true ]

Now the two candidates do not take the same argument. Our operator template takes a reference to non-const. In the case of two references, the one referring to the last cv-qualified type is preferred, which in this case would be the operator. Drop that const, and now your function is preferred, and you will see something printed.

C++ is the best.

Upvotes: 6

Related Questions