Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining out-of-line member template functions

Consider this (minimized) example:

template <typename Descriptor>
class hash_table
{
public:
  typedef int value_type;

  template <typename Argument, int Callback (value_type *, Argument)>
  void traverse (Argument);

  template <int Callback (value_type *)>
  void traverse_void ();
};

I defined a class template which has template member functions with non-type parameters. Note that Callback depends on value_type typedef. Now I want to define the functions themselves:

template <typename Descriptor>
template <typename Argument, int Callback (typename hash_table <Descriptor>::value_type *, Argument)>
void hash_table <Descriptor>::traverse (Argument) {}

template <typename Descriptor>
template <int Callback (typename hash_table <Descriptor>::value_type *)>
void hash_table <Descriptor>::traverse_void () {}

I get inconsistent errors from the compilers. The result does not depend on options, specifying the version of C++ standard (i.e., same for C++98, C++11 and C++14), but depends on the compiler.

GCC 6.0.0 (recent trunk, as well as several other versions) accepts this code.

Clang 3.7.0 (recent trunk) gives the following error:

test.cc:18:31: error: out-of-line definition of 'traverse_void' does not match any declaration in 'hash_table<Descriptor>'
void hash_table <Descriptor>::traverse_void() {}
                              ^~~~~~~~~~~~~
1 error generated.

EDG (Intel C++ Compiler v. 15.0.3) gives two errors:

test.cc(15): error: declaration is incompatible with function template "void hash_table<Descriptor>::traverse<Argument,Callback>(Argument)" (declared at line 7)
  void hash_table <Descriptor>::traverse (Argument) {}
                                ^

test.cc(19): error: declaration is incompatible with function template "void hash_table<Descriptor>::traverse_void<Callback>()" (declared at line 10)
  void hash_table <Descriptor>::traverse_void () {}
                                ^
compilation aborted for test.cc (code 2)

What is the expected behavior (according to the standard)? If the code is wrong, how do I fix the function definitions?

like image 503
Mikhail Maltsev Avatar asked Jul 18 '15 16:07

Mikhail Maltsev


People also ask

How would you define member function outside the class template?

Member functions of class templates (C++ only) You may define a template member function outside of its class template definition. The overloaded addition operator has been defined outside of class X . The statement a + 'z' is equivalent to a. operator+('z') .

Do template functions need to be inline?

Yes, you need the inline specifier there. The ODR (one-definition rule) states that there must be exactly one definition of a variable, function, class, enum or template.

Can member functions be declared as template?

The term member template refers to both member function templates and nested class templates. Member function templates are function templates that are members of a class or class template. Member functions can be function templates in several contexts.


1 Answers

Your code looks fine to me, I see no reason for it to not compile. Probably a bug on the compilers that disallow it. However, since [temp.param]:

A non-type template-parameter of type “array of T” or “function returning T” is adjusted to be of type “pointer to T” or “pointer to function returning T”, respectively.

You could simply switch Callback yourself to be a pointer-to-function. The behavior would be identical in all respects, with the added benefit that this code also compiles on clang.

like image 173
Barry Avatar answered Oct 24 '22 04:10

Barry