5

Why am I getting an error message when calling unary + with operator syntax? If I call it with function syntax, it is OK. Live demo.

template <int size>
struct Buffer { char buf[size]; };

template <class T>
struct Wrapper { void operator+() {} };

Wrapper<Buffer<-5>> a;

void f1() { +a; }               // error: Buffer<-5>::buf has negative size
void f2() { a.operator+(); }    // OK
Dr. Gut
  • 2,053
  • 7
  • 26
  • you might be invoking undefined behavior, this answer https://stackoverflow.com/questions/3783282/declaring-an-array-of-negative-length is for `C` but it might be applying to c++ as well. –  Jun 10 '20 at 23:09
  • Neither should instantiate `Buffer<-5>`. I would think that both should work, maybe this is a compiler bug? It's not to do with arrays, because the same thing happens when you replace `Buffer<-5>` with `std::tuple` (Or any other template class that can't be instantiated) – Artyer Jun 10 '20 at 23:42
  • I think that the operator inside a template is not visible. If you make it `friend` and add a parameter, then `f1` would compile instead of `f2`. I am surprise that the error is not shown on the declaration of the variable `a`. – Phil1970 Jun 11 '20 at 02:05
  • This is very close to being [a duplicate](https://stackoverflow.com/q/8379002/8586227), although that one doesn’t involve operators (and does involve a red herring of a cast). – Davis Herring Jun 11 '20 at 02:27

1 Answers1

5

The unqualified lookup invokes ADL, which needs to know if there are any friend functions defined in the associated classes. Buffer<-5> is one such, so it is instantiated. The fact that it’s syntactically obvious that it declares no friends doesn’t change the fact that the check for same involves completing the class type, which fails.

As an example let's put Buffer into namespace N, and operator+ into Buffer. If a's type is Wrapper<N::Buffer<5>> (5 rarher than -5), operator+ is found by ADL, and the code compiles (live demo):

template <class T>
struct Wrapper {};

namespace N {
    template <int size>
    struct Buffer {
        template <class T> friend void operator+(const Wrapper<T>&) {}
        char buf[size];
    };
}

Wrapper<N::Buffer<5>> a;

void f1() { return +a; }
Dr. Gut
  • 2,053
  • 7
  • 26
Davis Herring
  • 36,443
  • 4
  • 48
  • 76