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?
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') .
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.
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.
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 returningT
” is adjusted to be of type “pointer toT
” or “pointer to function returningT
”, 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With