When I specialize a (static) member function/constant in a template class, I'm confused as to where the declaration is meant to go.
Here's an example of what I what to do - yoinked directly from IBM's reference on template specialization:
===IBM Member Specialization Example===
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
int main() {
X<char*> a, b;
X<float> c;
c.f(10); // X<float>::v now set to 20
}
The question is, how do I divide this into header/cpp files? The generic implementation is obviously in the header, but what about the specialization?
It can't go in the header file, because it's concrete, leading to multiple definition. But if it goes into the .cpp file, is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?
So far I've got the specialization in the .cpp only, with no declaration in the header. I'm not having trouble compiling or even running my code (on gcc, don't remember the version at the moment), and it behaves as expected - recognizing the specialization. But A) I'm not sure this is correct, and I'd like to know what is, and B) my Doxygen documentation comes out wonky and very misleading (more on that in a moment a later question).
What seems most natural to me would be something like this, declaring the specialization in the header and defining it in the .cpp:
===XClass.hpp===
#ifndef XCLASS_HPP
#define XCLASS_HPP
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
/* declaration of specialized functions */
template<> char* X<char*>::v;
template<> void X<float>::f(float arg);
#endif
===XClass.cpp===
#include <XClass.hpp>
/* concrete implementation of specialized functions */
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
...but I have no idea if this is correct. Any ideas?
Usually you'd just define the specializations inline in the header as dirkgently said.
You can define specializations in seperate translation units though if you are worried about compilation times or code bloat:
// x.h:
template<class T> struct X {
void f() {}
}
// declare specialization X<int>::f() to exist somewhere:
template<> void X<int>::f();
// translation unit with definition for X<int>::f():
#include "x.h"
template<> void X<int>::f() {
// ...
}
So yes, your approach looks fine. Note that you can only do this with full specializations, thus it is often impractical to do this.
For details, see e.g. Comeaus template FAQ.
Put them all in a hpp file. Make the specializations and anything you define outside the class inline -- that'll take care of multiple definitions.
To answer one of your questions: is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?
If the compiler sees a definition which matches its requirements, then it will use it. Else it will generate normal function calls.
In your first code snippet, you supply a generic definition for X<T>::f(T arg), so the compiler will instantiate that for any T apart from float.
If you were to omit the generic definition, then the compiler would generate calls to, say, X<double>::f(double) and the linker would go searching for the definition which might end with a linker error.
To summarise: You can have everything in headers, because as templates you won't get multiple definitions. If you only have declarations, you will need definitions elsewhere for the linker to find later.
Using template void X<float>::f(float arg) { v = arg * 2; } instead.
Related
I have a library with a class templated on a size:
foo.hpp:
template <size_t N>
struct Foo {
void bar();
};
foo.cpp:
template <size_t N>
void Foo<N>::bar() {
...
};
I want the compiled version to be instatiated for a specific list of sizes which would be defined in the cpp file. In pseudocode, something like this
foo.cpp:
template <size_t N>
void Foo<N>::bar() {
...
};
for (const auto & size: {1,2,7,9})
template struct Foo<size>;
Right now, I am manually doing this (instatiating for each type), but this is error prone since I have several files that should be defined for the same size.
I am aware that I could move everything to the header file, and use some enable_if's to choose which sizes are valid. However, I want to hide the implementation details. Hence the current approach.
EDIT:
FWIW, I was hoping to avoid macros. I thought that something like this would work if you want a range of variables (e.g. 1,2,3,4...):
template<template<size_t> class E, size_t I = 1, std::enable_if_t<I >= 5> *unused = nullptr>
bool instatiator() {
return true;
}
template<template<size_t> class E, size_t I = 1, std::enable_if_t<I < 5> *unused = nullptr>
bool instatiator() {
E<I> e;
return instatiator<E, I + 1>();
}
bool unused = instatiator<Encoder>();
but I can't seem to get that working.
You could use an X macro approach for this:
valid_sizes.hpp
// Note: no include guards!!
PROCESS_SIZE(1)
PROCESS_SIZE(2)
PROCESS_SIZE(7)
PROCESS_SIZE(9)
#undef PROCESS_SIZE
foo.cpp
// ...
#define PROCESS_SIZE(n) template struct Foo<n>;
#include "valid_sizes.hpp"
bar.cpp
// ...
#define PROCESS_SIZE(n) some_other_use_of<n>;
#include "valid_sizes.hpp"
Alternatively, instead of a manual list, you could use Boost.Preprocessor:
process_sizes.hpp
#pragma once
#define PROCESS_SIZES(macro, data) BOOST_PP_SEQ_FOR_EACH(macro, data, (1)(2)(7)(9))
some header file
#define INSTANTIATE_CLASS(r, Name, size) template class Name<size>;
foo.cpp
#include "process_sizes.hpp"
// ...
PROCESS_SIZES(INSTANTIATE_CLASS, Foo)
bar.cpp
#include "process_sizes.hpp"
// ...
PROCESS_SIZES(INSTANTIATE_CLASS, Bar)
#define OTHER_SIZE_BASED_WORK(r, data, size) other_use_of<size>;
PROCESS_SIZES(OTHER_SIZE_BASED_WORK, whatever)
Note that explicit instantiation definitions must occur at namespace scope, so it's not possible put them inside a function like your attempted instantiator.
And also note that an implicit instantiation (such as would be caused by referring to the class in a context which requires it to be defined) is not "visible" outside the translation unit, so it cannot be used as a substitute for explicit instantiation.
In other words, having the same list of sizes do different things requires duplicating the list for each use, using macros, or using custom code generation outside of the C++ compilation pipeline. I consider macros the simplest and most maintainable of these.
In addition to #Angew answer:
xmacros can be in a different manner, allowing include guards and also avoiding having #include in the middle of the code:
valid_sizes.hpp
#pragma once
#define SIZES_TABLE(OP)\
OP(1) \
OP(2) \
OP(12)
foo.cpp
#include "valid_sizes.hpp"
// ...
#define INSTANTIATE(Size) template struct Foo<Size>;
SIZES_TABLE(INSTANTIATE)
#undef INSTANTIATE
You can recursively instantiate the Foo class with a helper class. Unfortunately you need to provide a call to each method of Foo in the constructor (the methods will not be called though), in order to provide the definitions to the linker:
// foo.cpp:
template <size_t S>
struct recursive_helper {
Foo<S> foo;
recursive_helper<S-1> r_helper;
recursive_helper() {
foo.bar();
foo.baz();
}
};
template <>
struct recursive_helper<0> {
Foo<0> foo;
recursive_helper() {
foo.bar();
foo.baz();
};
};
And then you instantiate the helper class:
template struct recursive_helper<6>;
Suppose a header file myheader.hxx defines a class template A in which a non-templated class B is defined (that does not depend on the template parameter of A):
template<class T>
class A {
class B {
// ...
};
};
Is it okay in this case to implement B in myheader.hxx, or do I need to write a separate myheader.cxx to avoid duplicate definitions at link time? Is this case handeled consistently by different compilers?
It's still either a template (or part of template, don't know the ultra-precise definitions) even if it's not the top-level template, so you need to should implement it in the header (technically, it can be in a source file if that's the only place it's used, but that probably defeats the purpose).
Note: if you're not going to implement its member functions inline with the class definition, you need syntax like:
template<typename T>
void A<T>::B::foo(...)
{
// ...
}
Also, because it's come up before, if B happened to have its own template parameter, it would be something like:
template<typename T>
template<typename T2>
void A<T>::B<T2>::foo(...)
{
// ...
}
Not:
template<typename T, typename T2>
void A<T>::B<T2>::foo(...)
{
// ...
}
Or if B didn't but B::foo did, it would be:
template<typename T>
template<typename T2>
// void A<T>::B::foo<T2>(...) // not this apparently
void A<T>::B::foo(...)
{
// ...
}
EDIT: apparently it's foo above instead of foo<T2> for a function, at least with GCC (so almost 100% sure that's standard behavior)...I'm sure some language lawyer will be able to explain why :)
Etc.
I'm code reviewing a colleagues code and found this:
Header file:
template<class T>
class MyClass
{
void Execute();
}
Cpp file:
void MyClass<int>::Execute()
{
// something
}
void MyClass<string>::Execute()
{
// something else
}
The code is specializing the function, but without using template specialization syntax. I guess it's working ok, but is it valid?
Yes, it's perfectly valid to specialize methods of a template class.
But your syntax is wrong, it should be: (sorry, didn't see you were missing the template<> initially. Just assumed it was there and thought you were asking about member function specialization.)
template<>
void MyClass<int>::Execute()
{
// something
}
template<>
void MyClass<string>::Execute()
{
// something else
}
You need only declare these in the header. If you implement them in the header as well, you'll need to mark them inline to prevent multiple definition.
When calling a method, the version that suits the call most is called. Otherwise, the default.
In your case, if you specialize the template with a class X and attempt to call Execute, you'll get a linker error because you haven't provided a default implementation, nor a specialization for Execute for X.
The question has already been answered, but let me draw attention to subtle differences between three cases.
Case 1: Specialization
header:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
template <> void Foo<int>::f();
source:
template <> void Foo<int>::f() { /* ... */ }
In this case, Foo<T>::f() can be called for any T. The definition for the general case is auto-generated from the template; the definition for Foo<int>::f() is the one provided. Having the specialization in the header alerts every consuming translation unit that a separate symbol is to be looked up, rather than to use the template.
Case 2: Definition
header:
template <typename T> struct Foo
{
void f();
};
source:
template <> void Foo<int>::f() { /* ... */ }
In this case, only Foo<int>::f() can be used; everything else will cause a linker error. Since there is no definition of the function in the template, every use of the template will cause a new symbol to be emitted, and only the one for Foo<int>::f() is provided by the shown translation unit.
Case 3: Flagrant error
header:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
source:
template <> void Foo<int>::f() { /* ... */ }
This is a violation of the one-definition rule, since there are now multiple definitions of Foo<int>::f().
This is the old syntax for explicit specialization. But I'm surprised that you are using a compiler which still accept it (g++ stopped around 4.0). To be conforming you need to prefix the specialization with template <>.
To answer the question in the title as originally written: absolutely. It's also valid to have a completely unrelated set of members in a specialization.
To answer the question in the code: looks to me like a compiler bug. The template <> is required.
I would like to have several different function definitions for a member function in a templated class. Something like this:
template <typename T>
class MyClass
{
void Foo();
T val;
//other functionality and data
};
//handles all types
template <typename T>
void MyClass<T>::Foo()
{
return val;
}
//handles a special type in a different way
template <>
void MyClass<float>::Foo()
{
return val + 5.0f;
}
I've tried implementing this as above and get a linker error for every special type I try to explicitly instantiate. The linker error mentions that the function has already been previously defined. Maybe I'm looking in the wrong places but I couldn't find any resources to help me figure out this problem :(
Q. Is this possible? If so, how do you do this and why does it work?
Thanks!
Here is a workaround that I frequently use. As it as been said before, you have to specialize the complete template. The idea is to make the method you want to specialize a static member of some struct (that should be nested and private for encapsulation reasons). Like this:
template< typename T >
class MyClass {
struct PerformFoo {
static void doFoo () {
std::cout << "Foo for general type" << std::endl;;
}
};
public:
void Foo () {
PerformFoo::doFoo();
}
};
template<>
struct MyClass< float >::PerformFoo {
static void doFoo () {
std::cout << "Foo for float" << std::endl;;
}
};
Now in your main, the code
MyClass< int > myInt;
myInt.Foo();
MyClass< float > myFloat;
myFloat.Foo();
prints
Foo for general type
Foo for float
on your terminal. By the way: this does not involve any performance penalty with modern compilers. Hope this helps you.
By defining the specialized member function as inline function you will get rid of the link error complaining the specialized member function having been defined elsewhere.
//handles a special type in a different way
template <>
inline void
MyClass<float>::Foo()
{
return val + 5.0f;
}
The reason being that a specialized function is no longer a function template, but a concrete function. Therefor it will be compiled several times when compiling source files that includes this header file which is why you get the "already defined" error.
Another solution is to move the implementation of the specialized function out of the header file and put it into the source file, meanwhile, declare the specialized function in the header file. Note that the declaration of the specialized member function must stay outside of the class definition:
/// Declare the specialized function in the header file but outside the
/// class definition.
template <> void MyClass<float>::Foo()
/// Define the specialized function in .cpp file:
template <>
void
MyClass<float>::Foo()
{
return val + 5.0f;
}
I've tried implementing this as above and get a linker error for every special type I try to explicitly instantiate.
What does that mean? If you explicitly specialize the template you cannot explicitly instantiate it anymore for the same template arguments. The whole purpose of an explicit specialization is to prevent the instantiation of it (which is a generated specialization) in favor of your explicit specialization.
So your description does not make sense to me. Just remember that you need to put definitions of templates and member functions of class templates in the header instead of in the .cpp file if you want to instantiate them implicitly. And that explicit specializations need to be declared to everyone who uses their template with their arguments.
// put this specialization into the header, for everyone to see
template <> void MyClass<float>::Foo();
It is not possible. When you specialize a template, you must specialize the entire template, which in this case means the entire class.
You can make foo a template function inside the template class. It is not exactly the same as what you are asking for, but it might meet your needs.
Update:
template<typename T> class Foo {
public:
template<typename R> void foo() {printf("This is foo\n");}
template<> void foo<float>() {printf("This is foo<float>\n");}
};
Or:
template<typename T> class Foo {
public:
template<typename R> void foo() {printf("This is foo\n");}
//template<> void foo<float>() {printf("This is foo<float>\n");}
};
template<> template<> void Foo<float>::foo<float>() {
printf("This is foo<float>\n");
}
along with:
int main(int argc,char * argv[])
{
Foo<int> iFoo;
iFoo.foo<int>();
Foo<float> fFoo;
fFoo.foo<float>();
return 0;
}
generates:
This is foo
This is foo<float>
The syntax for calling foo is a bit awkward.
If I have a template class specification like so,
template <typename T>
class MyClass {
public:
void fun1();
// ...
void funN();
};
template <typename T>
void MyClass<T>::fun1() {
// definition
}
// ...
template <typename T>
void MyClass<T>::funN() {
// definition
}
If I change the class template to something else, say I add an extra parameter:
template <typename T, typename U>
class MyClass {
// ...
};
Then I have to change each function definition (fun1, ..., funN) to agree with the class template specification:
template <typename T, typename U>
void MyClass<T,U>::fun1() { //... }
Are there any strategies for avoiding this? Could I use macros e.g.
#define DFLT_TEMPLATE template<typename T, typename U>
#define DFLT_CLASS class<T,U>
DFLT_TEMPLATE
void DFLT_CLASS::fun1() { // ... }
Or is this considered bad practice?
To me, the benefits of using a macro here are far overshadowed by the drawbacks. Yes, if you use a macro then if you ever need to add an additional template parameter, you'll only need to make a single modification. But anyone else reading your code is probably going to vomit.
I mean, are you going to do this for every template you have? Your code will become infested with ugly macros.
How many member functions do you have that this is an issue?
I think either they are small enough to be defined within the class template or the adaption of their algorithms to an additional template parameter would by far outweigh the replacement of those function headers.
Also, your editor ought to do this for you in no time anyway.
yes you could but don't forget to use "#undef DFLT_TEMPLATE" and "#undef DFLT_CLASS" at the end of file to avoid compiler warnings if your project have several templates with same macros definitions
Inheritation is better than macro.
If you want to change only a few functions and variables, make the specialized class inherit a common class that provides common functions/variables.
As far as possible, put the function definitions in the class template definition. It's a template, so unless you're using Comeau compiler, it's not as if they're going to be off in a different TU.
If the functions use something which is defined in between the class definition and the function definition, then you can play tricks to make that thing dependent on a template parameter even when "really" it isn't. For example:
template <typename T>
struct Foo {
void usebar();
};
struct Bar {
int a;
Foo<int> circularity; // circular dependency between Foo and Bar
Bar() : a(3) {}
};
template <typename T> void Foo<T>::usebar() {
Bar b;
std::cout << b.a << "\n";
}
Becomes:
// we only have to write "same" once
template <typename T, typename U>
struct same {
typedef U type;
};
struct Bar;
template <typename T>
struct Foo {
void usebar() {
typename same<T,Bar>::type b;
std::cout << b.a << "\n";
}
};
struct Bar {
int a;
Foo<int> circularity; // circularity gone
Bar() : a(3) {}
};
Or actually in this case just:
struct Bar;
template <typename T, typename B = Bar>
struct Foo {
void usebar() {
B b;
std::cout << b.a << "\n";
}
};
struct Bar {
int a;
Foo<int> circularity;
Bar() : a(3) {}
};
All cases support the following code:
int main() {
Foo<int> f;
f.usebar();
}
I would consider this approach bad practice. What you are complaining about is that you have changed your design (you need an extra template parameter) and now want a kludge to save on typing?
Introducing macros is going to decrease the readability of your code. Preprocessor definitions certainly have their place, but personally I'd never advocate one on the grounds that I can't be bothered to change my functions.
There are probably some (more or less bad) workarounds, but you definitely point out a " missing" feature of C++: class namespace extension.
Some people already proposed to extend C++ in this way:
http://www.lrde.epita.fr/dload//20080709-Seminar/ordy-classnamespaces.pdf
namespace foo
{
class bar
{
typedef int baz_t;
baz_t my_method ();
};
}
namespace class foo::bar
{
baz_t my_method ()
{
// ...
}
}
--
Using a macro is not a good idea (usual things about macros ....).
I would prefer, at worst, write function members definitions inline in this case, or even better use an editor than can help you easily update your class definition.
Macros are bad because they let you write code editing functions where you are supposed to write programs.
If you want to edit code, use your editor (sed, M-x replace-*, Find&Replace ...)