0

I'm trying to implement an operator overload for a class such as:

template<class T> class A{
public:
    T val;

    A<T>& operator=(const T& v) {
        this->val = v;
        return *this;
    }
}

So I can do:

A<bool> obj;
obj = true; // instead of obj.val = true
obj = false;

This works fine.

However, if I do this:

A<bool> obj;
obj = 123123; // bool is not a number!

It still works! Can I somehow prevent that?

I tried marking the overload explicit like this:

explicit A<T>& operator=(const T& v) { ... }

but I get an error:

error C2071: 'A<T>::operator =': illegal storage class

Is it even possible to do this?

rev
  • 1,861
  • 17
  • 27
  • 1
    Perhaps these? http://stackoverflow.com/questions/12877546/how-do-i-avoid-implicit-casting-on-non-constructing-functions-c http://stackoverflow.com/questions/9458741/with-explicitly-deleted-member-functions-in-c11-is-it-still-worthwhile-to-inh – Salmonstrikes Apr 03 '15 at 03:12
  • @Salmonstrikes no, because they only work for individual functions (not _class_ methods), and they're specializations on specific types, not on all types – rev Apr 03 '15 at 03:14
  • The first of Salmon's links gives what you want – M.M Apr 03 '15 at 03:18

1 Answers1

2

As suggested in comments, make a deleted template function that matches everything except the one type you want to allow:

template<class T> class A
{
public:
    T val;

    A & operator=(T const &v) {
        val = v;
        return *this;
    }

    template<class U>
    A & operator=(U const &v) = delete;
};

int main()
{
    A<bool> a;
    a = true;
    a = 1;        // error: use of deleted function
}

If you are going to do this a lot, you can offload the heavy lifting to a helper class:

template<typename T>
struct exact
{
    T const &t;
    exact(T const &t): t(t) {}

    template<typename U> 
    exact(U u) = delete;
};

template<class T> class A
{
public:
    T val;

    A &operator=(exact<T> v) {
        val = v.t;
        return *this;
    }
};
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Note, you don't need to write `A` inside the class, just `A` – M.M Apr 03 '15 at 03:23
  • Amazing, I just changed the `= delete;` to `{ static_assert(false, "[...] error [...]"); }`. Could you explain why is the second function getting called instead of the first one though? – rev Apr 03 '15 at 03:27
  • 1
    @AcidShout [see here](http://stackoverflow.com/questions/29324762/why-is-template-overload-a-better-match-than-a-simple-conversion) for explanation of that – M.M Apr 03 '15 at 03:35
  • 1
    @AcidShout For `A` the `T` is `bool` therefore there is a member function `A& operator=(const bool&)` and `template A& operator=(const U&)` which is for any type. Therefore calling it with '1' (i.e., an integer) calls the `template` overload. Note: when you call it using a bool the non-templated function wins during overload resolution. – James Adkison Apr 03 '15 at 03:36