Is it O.K. to define virtual function of class template outside its body? Virtual function can not be inlined, but to avoid multiple definitions in compilation units they shall be marked inline (assuming that template headers will be included in multiple source files). On the other hand compiler is free to ignore inline, so this seems valid. By an example, is the code below correct:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
?
BTW gcc (3.4.2) allows to omit inline before definition of function f(T val) but not before analogous function of regular class. Is it only gcc's behaviour?
Yes, it's OK even without inline. It works the same for ordinary member functions and static variables:
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
Standard quote: (3.2/5)
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements ...
The requirements basically say the two definitions have to be identical.
It doesn't work in case of regular classes. There has to be at most one definition in the whole program.
You can define template methods outside the class definition, in the same header, without using inline and without receiving multiple definition errors.
That's because a template function doesn't generate a definition itself, if it's not fully specialized. To prove my point, the following:
void C<int>::f(int)
{
}
will result in a linker error, as the function has a definition in this case. (provided you include this in multiple translation units. If you mark it inline:
inline void C<int>::f(int)
{
}
the error no longer occurs.
You can define the functions there, as long as any code which needs to instantiate the function in question has visibility of that code at compile time (not link time).
It's quite common to separate a template into 2 files, one being a traditional header, and the second being the implementation, as with non-templated functions and their implementation. The only difference is that you need to #include the template implementation file as well as the header when you want to use it.
Related
Is it O.K. to define virtual function of class template outside its body? Virtual function can not be inlined, but to avoid multiple definitions in compilation units they shall be marked inline (assuming that template headers will be included in multiple source files). On the other hand compiler is free to ignore inline, so this seems valid. By an example, is the code below correct:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
?
BTW gcc (3.4.2) allows to omit inline before definition of function f(T val) but not before analogous function of regular class. Is it only gcc's behaviour?
Yes, it's OK even without inline. It works the same for ordinary member functions and static variables:
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
Standard quote: (3.2/5)
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements ...
The requirements basically say the two definitions have to be identical.
It doesn't work in case of regular classes. There has to be at most one definition in the whole program.
You can define template methods outside the class definition, in the same header, without using inline and without receiving multiple definition errors.
That's because a template function doesn't generate a definition itself, if it's not fully specialized. To prove my point, the following:
void C<int>::f(int)
{
}
will result in a linker error, as the function has a definition in this case. (provided you include this in multiple translation units. If you mark it inline:
inline void C<int>::f(int)
{
}
the error no longer occurs.
You can define the functions there, as long as any code which needs to instantiate the function in question has visibility of that code at compile time (not link time).
It's quite common to separate a template into 2 files, one being a traditional header, and the second being the implementation, as with non-templated functions and their implementation. The only difference is that you need to #include the template implementation file as well as the header when you want to use it.
I am working on a template function in a class:
class Data {
public:
template <typename T>
std::byte* serialize(const T& object) { /* serialize */ }
};
and I noticed that Data::serialize<Object> is instantiated in every compilation unit. For classes I could do, e.g.
extern template class Class<Object>;
in the header file and place
template class Class<Object>
to instantiate the Class<Object> only once and let the linker resolves the issue. Is there a way I do similar thing for functions and member functions?
It works exactly the same.
Explicit instantiation declaration in the header:
extern template std::byte* Data::serialize<Object>(const Object&);
And explicit instantiation definition in one translation unit:
template std::byte* Data::serialize<Object>(const Object&);
(<Object> is optional because it can be deduced from the const Object& parameter.)
However, consider that while this may reduce compilation time, it can also negatively affect compiler optimizations, because you make it harder to inline the function (at least without link-time optimization). The resulting binary will contain only one definition of the function template specialization anyway, whether you use explicit instantiation or not.
I have defined a simple class-template with one member function. It is defined outside the class with an additional (explicit) specialization, also defined outside the class. All in one headerfile. If you include this header in multiple translation units you get a linker error due to One-Definition-Rule.
// Header with a template
template <class T>
class TestClass
{
public:
TestClass() {};
~TestClass() {};
bool MemberFunction();
};
template <class T>
bool TestClass<T>::MemberFunction()
{
return true;
}
template <>
bool TestClass<double>::MemberFunction()
{
return true;
};
Everything fine so far. But If I put the definition of the member function inside the class body, the linker error disappears and the functions can be used throughout different translation units.
// Header with a template
template <class T>
class TestClass
{
public:
TestClass() {};
~TestClass() {};
bool MemberFunction()
{
return true;
}
};
template <>
bool TestClass<double>::MemberFunction()
{
return true;
};
My question is why does it work that way? I use MSVC 2012. ODR has some exceptions on templates what I first thought to be the reason. But the definition of the "Base" function inside/outside the class makes the difference here.
14.7/5 says
5 For a given template and a given set of template-arguments,
an explicit instantiation definition shall appear at most once in a program,
an explicit specialization shall be defined at most once in a program (according to 3.2), and
both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the explicit
instantiation follows a declaration of the explicit specialization.
An
implementation is not required to diagnose a violation of this rule.
The second bullet applies to your case. The ODR defined in 3.2 says the same thing, albeit in a less distilled form.
Regardless of where and how the non-specialized version of member function is defined, the specialized version definition
template <> bool TestClass<double>::MemberFunction()
{
return true;
};
has to go into a .cpp file. If kept in the header file, it will produce an ODR violation once the header gets included into more than one translation unit. GCC reliably detect this violation. MSVC seems to be less reliable in that regard. But, as the quote above states, an implementation is not required to diagnose a violation of this rule.
The header file should only contain a non-defining declaration of that specialization
template <> bool TestClass<double>::MemberFunction();
The fact that in MSVC the error appears or disappears depending on such seemingly unrelated factor as how the non-specialized version of the function is defined must be a quirk of MSVC compiler.
After further research, it appears that MSVC implementation is actually broken: its behavior goes beyond what's allowed by the "no diagnostic is required" permission given by the language specification.
The behavior you observed in your experiments in consistent with the following: declaring the primary function template as inline automatically makes the explicit specialization of that template inline as well. This is not supposed to be that way. In 14.7.3/14 the language specification says
An explicit specialization of a function template is inline only if it
is declared with the inline specifier or defined as deleted, and
independently of whether its function template is inline.
Consider the following construct:
//! Templated singleton.
/*!
Template wrapper enforcing the singleton behavior.
*/
template <class T>
class TSingleton
{
private:
//! Singleton instance pointer.
static T* instance;
//! private constructor.
TSingleton() { }
//! private empty copy constructor.
TSingleton(const TSingleton<T>& sourceObject) {}
public:
//! Static singleton instance getter.
static T* GetInstance()
{
if (instance == 0)
instance = new T();
return instance;
}
};
template <class T> T* TSingleton<T>::instance = 0;
This template class and the definition of the static instance are written in the same header file. For a non-template class, this causes a link-time error due to multiple symbols being defined for the instance static member. It seems intuitive for this to happen with templates as well, thus one must separate the definition and put it in a .cpp file. But templates are usually declared and defined in header-like files. What is it that allows this syntax to be valid and functional for template classes?
There a wikipedia link on this, but it does not provide a clear explanation on what happens in case of template classes.
This works because [basic.def.odr]/5 explicitly allowed templates to be duplicated:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. ...
The requirements are quite lengthy, so I won't duplicate them here, but essentially they state that each duplicate definition must be identical (otherwise the program has undefined behaviour).
Given:
template<class T>
struct test {
void foo(int b);
void testFunc( int a )
{
}
};
void test::foo(int b)
{
}
template<>
void test<float>::testFunc( int a )
{
}
void someFunction()
{
}
We know that "test::foo" has a declaration in the test class, and a definition outside the class definition.
We also know that "someFunction" has a declaration which is also its definition.
In like manner "test::testFunc" (non-specialized), has a declaration which is also its definition.
Is the specialization function "test<float>::testFunc" said to be declared with the declaration of "testFunc" inside of class "test" and defined separately, or is its declaration also the definition?
The explicit specialization in your example is a declaration that is also a definition. You could also declare it separately:
template<>
void test<float>::testFunc( int a );
and if the function was used, the linker would expect it to be defined somewhere.
The declaration inside the class is the declaration and definition of the member function template.
BTW, foo should be defined like this:
template <class T>
void test<T>::foo(int b)
{
}
I would like to add to the useful answer #Vaughn provided.
In the template definition of test, you have a non-defining member function declaration and also a defining member function declaration. But that function definition and declaration is associated with the surrounding template test<T>, and not with the class test<float> that will eventually be instantiated from it!
If you implicitly instantiate test<float> from that template, for example by using the ::-operator (scope) on it, or by creating a variable definition having that type and so on, then declarations but not necessarily the definitions of all members are also implicitly instantiated. All of them are associated with and members of test<float>.
So when you write your explicit specialization for test<float>::testFunc, because you used :: to look into the class test<float>, that class is being implicitly instantiated and with it all its member declarations.
The definition of test<float>::testFunc is only instantiated when it is required (for example when you call it).
The explicit specialization you declared then redeclares the member function that was previously implicitly instantiated and provides a definition that is associated with test<float>. It is a real function and cannot be safely defined in a header unless it is marked inline - otherwise you risk "defined more than once" errors when you include its header multiple timrs.
To summarize what declarations and definitions exist for testFunc and where they come from:
By your template definition:
test<T>::testFunc(int);
test<T>::testFunc(int) { }
Generated specialization by the compiler from test<T>::testFunc(int);
test<float>::testFunc(int);
Explicit specialization by you of test<T>::testFunc(int);
test<float>::testFunc(int);
test<float>::testFunc(int) { }
In particular, there is no generated definition of test<float>::testFunc. If there was, then your code would be ill-formed, without diagnostics required, because the generated definition would interfere with your explicit specialization that provided a definition for the same function. But such a thing can only happen if you cause its instantiation before explicitly specializing it. So if you move the explicit specialization definition into a .cpp file (if you don't want to make it inline), put an explicit specialization declaration, like #Vaughn demonstrated, into the header.