9

I'm attempting to figure out why some code that I have won't compile and I done a fair bit of reduction an anonymizing to end up with this example:

#define NULL ((void*)0)
template<typename T>
class a {
public:
  template<bool b>
  T * amem() {
    return NULL;
  }
};

template<typename T>
class b {
public:
  a<T>* ap;

  template <bool b>
  T * m() {
    return ap->amem<b>();
  }
};

int main()
{
  return 0;
}

Depending on the compiler that I use and the names of the variables I get different errors. They are all centered around this line, though:

    return ap->amem<b>();

Compiling using clang++ [Apple clang version 4.0 (tags/Apple/clang-421.0.57) (based on LLVM 3.1svn)], I get the following message:

tmp.cpp:18:26: error: expected expression
      return ap->amem<b>();
                         ^
1 error generated.

Compiling using g++ [i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1], I get the following message:

tmp.cpp: In member function ‘T* b<T>::m()’:
tmp.cpp:18: error: expected primary-expression before ‘>’ token
tmp.cpp:18: error: expected primary-expression before ‘)’ token

Mysteriously (to me, anyway). If I change the name of amem to m, I no longer get any errors from g++, but I get the same error from clang++.

I'm sure there is something here that I just don't understand? Does anyone know what expression clang and gcc are looking for? Does anyone know how to solve this problem?

If this is a compiler bug (seems doubtful), does anyone know any workarounds that don't involve converting amem into a function with a bool parameter (rather than a template)? I've done this already and I can confirm that this works around the issue, but this is inside a hot loop and the code that is switched on by b is a memory allocation that probably shouldn't be in a hot loop.

Arlen Cox
  • 374
  • 1
  • 2
  • 8

2 Answers2

25

Need to add the template keyword:

return ap->template amem<b>();

Please read Where and why do I have to put the “template” and “typename” keywords? for an in-depth explanation.

Community
  • 1
  • 1
Jesse Good
  • 46,179
  • 14
  • 109
  • 158
  • Crazy. I didn't know about that use of template. I've used it for types many times, but never for functions. – Arlen Cox Nov 11 '12 at 23:48
3

In the context where you call

return ap->amem<b>();

the name amem is a dependent name: If such a beast indeed refers to a member function template, you need to say so by adding the keyword template:

return ap->template amem<b>();

BTW, note that you shall not define NULL! If you need a definition of the abomination you should include, e.g., cstddef. Best you use just 0 or nullptr when using C++ 2011.

Dietmar Kühl
  • 141,209
  • 12
  • 196
  • 356
  • Thanks for the answer. I never define NULL in actual code, but I did it here to make the example as self contained as possible. – Arlen Cox Nov 12 '12 at 00:02