1

I have, at some point in my code, an overload like this

template<int L>
template<int M>
inline StaticMemory<L>& StaticMemory<L>::operator =(const StaticMemory<M>& _m)
{
   if (this != &_m) { //Problem here!
      set_ui(this->mem, _m.mem, L, M);
   }
   return *this;
}

What happens is that the check I highlighted is basically wrong, because when L != M the pointer comparison is notvalid, unless I cast it. I could cast the pointer probably, but is there a way to use the std::enable_if to maybe write two different versions of such operator?

Thx

user8469759
  • 2,522
  • 6
  • 26
  • 50
  • What are you asking? Are you asking if you can write one version of the function for when `L == M` and another version of the function for when `L != M`? – Jonathan Mee Dec 01 '16 at 11:58
  • Yes, that's what I'm asking. – user8469759 Dec 01 '16 at 11:58
  • The call to have `M == L` is not trivial as it appears. Only a explicit call will do that: `l1->operator=(l2);` else the copy assignment will be call. – Jarod42 Dec 01 '16 at 12:56
  • I don't understand, would the case L == M correctly overload the assignment operator? – user8469759 Dec 01 '16 at 12:57
  • @user8469759: The case `M == L` is special as it is *similar* to *copy assignment* (which is not *template*). And the *copy assignment* is taken when you provide `StaticMemory`. That's why the solution with `std::enable_if` (or solution with specialization) does't fix your issue and you have to provide the *copy assignment* directly. – Jarod42 Dec 01 '16 at 23:42
  • I'm not sure I understand why `M == L` is similar to copy assignment and not equal. – user8469759 Dec 02 '16 at 11:26

2 Answers2

3

I think, it is solvable without std::enable_if

Just write additional operator= like this:

template<int L>
inline StaticMemory<L>& StaticMemory<L>::operator =(const StaticMemory<L>& _m)
{
    if (this != &_m) { //There are no problem here!
        set_ui(this->mem, _m.mem, L, L);
    }
    return *this;
}

Which will work if StaticMemory template argument is the same.

If they are different, your example code shall work, where you can cast whatever you want

Edit: proof of correctness:

#include <iostream>
template <int I>
struct Temp {
    template <int L>
    void operator=(const Temp<L>&) {
        std::cout << "Called with L\n";
    }
    void operator=(const Temp<I>&) {
        std::cout << "Called with I\n";  
    }
};

int main() {
    Temp<1> t1;
    Temp<2> t2;
    t1 = t1;
    t1 = t2;
}

Output here is:

Called with I
Called with L
Starl1ght
  • 4,422
  • 1
  • 21
  • 49
  • I'm sorry I have a question, you're suggesting to implement both of them? Wouldn't there be some conflicts? because when M = L which one would the compiler generate? – user8469759 Dec 01 '16 at 11:38
  • @user8469759 Yep, I suggest to implement them both. There should be no conflicts, and and if M == L, my template shall be called, if M != L - yours. – Starl1ght Dec 01 '16 at 11:59
  • @user8469759 added, proofs – Starl1ght Dec 01 '16 at 12:10
  • @Starl1ght I believe the point is that he doesn't want to have to test if the values are equal. He wants the compiler to do that for him. – Jonathan Mee Dec 01 '16 at 12:14
  • @JonathanMee Either I misunderstood you, or compiler still test it, getting correct operator, based on operator argument, without enable_if – Starl1ght Dec 01 '16 at 12:15
  • @Starl1ght Given `constexpr int foo()` and `constexpr int bar()`, say that I'm doing this: `StaticMemory() = StaticMemory()` should I use the inequal or equal version of the assignment operator? – Jonathan Mee Dec 01 '16 at 12:26
  • @JonathanMee matters of foo and bar values, compiler should pick necessary overload after processing constexpr's – Starl1ght Dec 01 '16 at 12:30
  • 1
    Ugh, yes, you're right... and I clearly need to go wake up now. – Jonathan Mee Dec 01 '16 at 12:32
  • @Starl1ght: And if you remove `void operator=(const Temp&)`, only `Called with L` will be printed. And BTW, return type should be `Temp&` – Jarod42 Dec 01 '16 at 12:39
  • @Jarod42 I know, this is not necessary here – Starl1ght Dec 01 '16 at 12:41
  • I should really review some basic concepts of C++. Although these templates are driving me crazy. – user8469759 Dec 01 '16 at 12:52
1

The following is not used as copy assignment

template <int L>
template <int M>
Temp<L>& Temp<L>::operator=(const Temp<M>&);

Copy assignment is only

template <int L>
Temp<L>& Temp<L>::operator=(const Temp<L>&);

And so yes, you have to write both overloads in your case.

The way to call the template assignment (the first overload) with same type is to call is explicitly, something like:

this->operator=<L>(rhs);
Jarod42
  • 203,559
  • 14
  • 181
  • 302