Reputation: 1827
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
Upvotes: 0
Views: 344
Reputation: 67723
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.
Upvotes: 3