0

Why do I get error "reference to non-static member function must be called":

<source>:35:19: error: reference to non-static member function must be called

    list_.front().Set<Flags::First>(true);

    ~~~~~~~~~~~~~~^~~

<source>:40:10: note: in instantiation of member function 'List<int>::Set' requested here

    list.Set();

         ^

<source>:13:8: note: possible target for call

  void Set(bool value) {

       ^

1 error generated.

Compiler returned: 1

when I try to compile this code with clang 7.0.0?

#include <iostream>
#include <list>
using namespace std;

enum class Flags : uint8_t {
    First  = 1,
    Second = 2
};

class Header {
public:
  template <Flags flag>
  void Set(bool value) {
       flags_ = static_cast<Flags>(
           value
           ? (static_cast<uint8_t>(flags_) | static_cast<uint8_t>(flag))
           : (static_cast<uint8_t>(flags_) & (~static_cast<uint8_t>(flag))));
  }

private:
  Flags flags_{};
};

template <class T>
class List {
public:
    void Set();

private:
    std::list<Header> list_;
};

template <class T>
void List<T>::Set() {
    list_.front().Set<Flags::First>(true);
}

int main() {
    List<int> list;
    list.Set();
    return 0;
}

See here: https://godbolt.org/z/KXttBb

york.beta
  • 1,717
  • 13
  • 16

1 Answers1

2

We can break down both how to diagnose this, and how and why the fix works.

<source>:35:19: error: reference to non-static member function must be called

OK, so clang thinks that something names a non-static member function, and that the expression you're using it in is not a function call:

list_.front().Set<Flags::First>(true);

~~~~~~~~~~~~~~^~~

It's telling us pretty explicitly that it recognizes Set as a non-static member function, but it thinks that Set<Flags::First>(true) is not a function call.

Obviously that's exactly the right syntax for calling a function template, so the problem is that clang isn't treating Set as a function template.


At this point, definitely read the question linked in comments above, and the accepted answer.

...


Right, now you've read that, it's obvious that Set is a dependent function name, and we can resolve the problem by adding template like so:

list_.front().template Set<Flags::First>(true);

but this still leaves open the question of why the name is dependent. I mean, reading the code, we know that list_.front() must have type Header&, right?

So let's try writing it out explicitly:

Header &front = list_.front();
front.Set<Flags::First>(true);

and we see (still with clang 8 or 9) that this now works without the extra template. If you write auto &front, the problem returns.

FWIW, this shows up in clang 8 and 9, but disappears in clang 10, and never seems to occur in GCC. So, it may be a bug, but at least you now know how to diagnose it and how to work around it.

Useless
  • 55,472
  • 5
  • 73
  • 117