C++ Class Template Specialization - c++

I am new to programming in C++ and I have encountered a problem that I cannot seem to solve when enforcing separate compilation. I am trying to specialize my class tokenize to add a dtor for a specific type (istream). I have the following:
#ifndef __TOKENIZER_H__
#define __TOKENIZER_H__
#include <fstream>
#include <string>
template <class T>
class base {
// ... some methods/member variables.
};
template <class T>
class tokenizer : public base<T> {
public:
tokenizer(T &in);
};
template <>
class tokenizer<std::ifstream> : public base<std::ifstream> {
public:
tokenizer(std::ifstream &in);
~tokenizer();
};
#endif
... and:
#include "tokenizer.h"
#include <fstream>
#include <iostream>
#include <locale>
using std::ifstream;
using std::istream;
using std::string;
// [BASE]
// ... code for those functions.
// [TOKENIZER]
// See header file.
template <class T>
tokenizer<T>::tokenizer(T &in) : base<T>(in) { }
// See header file.
template <>
tokenizer<ifstream>::tokenizer(ifstream &in) : base<ifstream>(in) { }
// See header file.
template <>
tokenizer<ifstream>::~tokenizer() {
delete &(base<ifstream>::in);
}
// Intantiating template classes (separate compilation).
template class base<std::ifstream>;
template class base<std::istream>;
template class tokenizer<std::ifstream>;
template class tokenizer<std::istream>;
... however I get the following error:
tokenizer.cc:62: error: template-id ‘tokenizer<>’ for ‘tokenizer<std::basic_ifstream<char, std::char_traits<char> > >::tokenizer(std::ifstream&)’ does not match any template declaration
tokenizer.cc:66: error: template-id ‘tokenizer<>’ for ‘tokenizer<std::basic_ifstream<char, std::char_traits<char> > >::~tokenizer()’ does not match any template declaration
I am compiling with g++. If someone can kindly point out what I am missing and a possible explanation then that would be fantastic. I am confused how templates work with separate compilation (defns/decl separated).

[temp.expl.spec]/5 states:
Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. However, template<> is used in
defining a member of an explicitly specialized member class template that is specialized as a class template.
It also provides the following example (I'll only quote some excerpts):
template<class T> struct A {
template<class U> struct C { };
};
template<> struct A<int> {
void f(int);
};
// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { /∗ ... ∗/ }
template<> template<class U> struct A<char>::C {
void f();
};
// template<> is used when defining a member of an explicitly
// specialized member class template specialized as a class template
template<>
template<class U> void A<char>::C<U>::f() { /∗ ... ∗/ }
As far as I know, once you've explicit specialized a class template, you've created a "normal class". It's obviously not a template any more (you cannot create classes from the specialization), but a type with some <..> in its name.
In your case, that just means leave out the template<> before
// See header file.
//template <>
tokenizer<ifstream>::tokenizer(ifstream &in) : base<ifstream>(in) { }
// See header file.
//template <>
tokenizer<ifstream>::~tokenizer() {
delete &(base<ifstream>::in);
}
With regard to your request on clarification of the combination of separate compilation with templates:
When you use a class template to create an object (e.g. std::vector<int> v) or call a function template (e.g. std::sort(begin(v), end(v))), you're dealing with specializations of the templates. std::vector<int> is a specialization of the class template std::vector.
When a specialization is required in a TU, it might be necessary to produce it from the class template. This is called instantiation. An explicitly specialized template won't be instantiated implicitly (it already is specialized). That is, your specialization tokenizer<ifstream> doesn't have to be instantiated in any TU.
Templates itself don't work with separate compilation for these reasons. However, you can use explicit instantiations and explicit specializations to provide the benefits of separate compilation for specializations of templates. For example:
[header.hpp]
template<class T> void foo(T);
extern template void foo<int>(int);
[impl.cpp]
#include "header.hpp"
template<class T> void foo(T) { return T{} };
template void foo<int>(int); // force instantiation
[main.cpp]
#include "header.hpp"
int main()
{
foo<int>(42); // no instantiation will occur
}
In main.cpp we couldn't instantiate the definition of foo, as the definition is not available. We could instantiate the declaration. There's also an explicit instantiation declaration, which prevents any implicit instantiation. In another TU (impl.cpp), we did instantiate foo<int> via an explicit instantiation definition. This requires the definition of f to exist and instantiates the definition. The rest is similar to normal functions: We have two declarations and one definition.
Similarly, for class templates: If the definition of a class is required in a TU, we need to either instantiate the template or we need to have an explicit specialization (an explicit instantiation definition is not possible here AFAIK). This is exactly the OP's example.
If the definition of the class is not required, we can use something similar to the PIMPL idiom:
[header.hpp]
template<class T>
class foobar;
struct s
{
foobar<int>* p;
void f();
}
[impl.cpp]
#include "header.hpp"
template<class T> class foobar { int i; }
void s::f() { p = new foobar{42}; }
[main.cpp]
int main()
{
s obj;
obj.f();
}

Related

Does template explicit instantiation work with forward-declared-types?

If I have a template class with some method defined in the .cpp file instead of the .h file, I can use explicit instantiation to get the compiler to avoid unresolved externals.
But would it work if the explicit instantiation is declared using a forward-declared type ?
template <typename T> struct Template
{
void someFunc(); //defined in the .cpp file
}
class A;
template Template<A>;
Would it work if A is finally not defined and Template<A> not used ?
First of all. The compiler only generates code if the template is instantiated (in your example no code is generated because there is no instantiation). Second, you pass a type template argument. Here the compiler would be allowed to safely create an instance.
In your example you do not use the type somewhere, but if you would e.g. to define a function, my first sentence would apply again, and the function is just generated upon instantiation somewhere.
Just at this moment the compiler must have all the knowledge to generate the code.
// Example program
#include <iostream>
template <typename T> struct Template
{
void someFunc(); //defined in the .cpp file
};
class A;
Template<A> foo;
However, if you create a template taking a non-type parameter. It will fail because the type definition is incomplete, as you were concerned of.
// Example program
#include <iostream>
#include <string>
class A;
template <A parm> struct Template
{
void someFunc() {
parm.foo();
}
};
A a;
using foo = Template<a>;
The same for this example. Here you would create an object a and of course the compiler needs to know more about the type. This is why it fails.
// Example program
#include <iostream>
template <typename T> struct Template
{
T a;
};
class A;
Template<A> foo;
Hope this helps.

c++ class template specialization, without having to reimplement everything

I have a templatized class like so :
template<typename T>
class A
{
protected:
std::vector<T> myVector;
public:
/*
constructors + a bunch of member functions here
*/
}
I would like to add just ONE member function that would work only for 1 given type of T. Is it possible to do that at all without having to specialize the class and reimplement all the other already existing methods?
Thanks
The simplest and cleanest solution is to use a static_assert() in the body of a method, rejecting other types than the selected one (in the below example only integers are accepted):
#include <type_traits>
#include <vector>
template <typename T>
class A
{
public:
void onlyForInts(T t)
{
static_assert(std::is_same<T, int>::value, "Works only with ints!");
}
protected:
std::vector<T> myVector;
};
int main()
{
A<int> i;
i.onlyForInts(1); // works !
A<float> f;
//f.onlyForInts(3.14f); // does not compile !
}
OK CASE DEMO
NOK CASE DEMO
This utilizes the fact that a compiler instantiates a member function of a class template only when one is actually used (not when the class template is instantiated itself). And with the above solution, when a compiler tries to do so, it fails due to the execution of a static_assert.
C++ Standard Reference:
§ 14.7.1 Implicit instantiation [temp.inst]
Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[ Example:
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<char>* p; // instantiation of class Z<char> not required
Z<double>* q; // instantiation of class Z<double> not required
a.f(); // instantiation of Z<int>::f() required
p->g(); // instantiation of class Z<char> required, and
// instantiation of Z<char>::g() required
}
Nothing in this example requires class Z<double>, Z<int>::g(), or Z<char>::f() to be implicitly
instantiated. — end example ]
Yes, it's possible in C++03 with CRTP (Curiously recurring template pattern):
#include <numeric>
#include <vector>
template<typename Derived, typename T>
struct Base
{
};
template<typename Derived>
struct Base<Derived, int>
{
int Sum() const
{
return std::accumulate(static_cast<Derived const*>(this)->myVector.begin(), static_cast<Derived const*>(this)->myVector.end(), int());
}
};
template<typename T>
class A : public Base<A<T>, T>
{
friend class Base<A<T>, T>;
protected:
std::vector<T> myVector;
public:
/*
constructors + a bunch of member functions here
*/
};
int main()
{
A<int> Foo;
Foo.Sum();
}
As an alternative solution, which works also in plain C++03 (as opposed to static_assert or enable_if solutions), you may add extra defaulted template argument which will let you have both
specialized and unspecialized version of class. Then you can inherit your specialized version from the unspecialized one.
Here is a sample snippet:
#include <vector>
template<typename T, bool unspecialized = false>
class A
{
protected:
std::vector<T> myVector;
public:
void setVec(const std::vector<T>& vec) { myVector = vec; }
/*
constructors + a bunch of member functions here
*/
};
template<>
class A<int, false> : public A<int, true>
{
public:
int onlyForInt() {
return 25;
}
};
int main() {
// your code goes here
std::vector<int> vec;
A<int> a;
a.setVec(vec);
a.onlyForInt();
return 0;
}
The drawbacks of this solution is the need to add constructor forwarders, if class
has non-trivial constructors.
The static_assert technique by #PiotrS. works nicely. But it's also nice to know that you can specialize a single member function without code duplication. Just give the generic onlyForInts() an empty no-op implementation, and specialize it out-of-class for int
#include <vector>
template <typename T>
class A
{
public:
void onlyForInts(T t)
{
// no-op
}
protected:
std::vector<T> myVector;
};
template<>
void A<int>::onlyForInts(int t)
{
// works
}
int main()
{
A<int> i;
i.onlyForInts(1); // works !
A<float> f;
f.onlyForInts(3.14f); // compiles, but does nothing !
}
Live Example.
This technique comes in handy if you want to have int specific behavior without completely disabling the generic behavior.
One approach not given yet in the answers is using the standard library std::enable_if to perform SFINAE on a base class that you inherit to the main class that defines appropriate member functions.
Example code:
template<typename T, class Enable = void>
class A_base;
template<typename T>
class A_base<T, typename std::enable_if<std::is_integral<T>::value>::type>{
public:
void only_for_ints(){/* integer-based function */}
};
template<typename T>
class A_base<T, typename std::enable_if<!std::is_integral<T>::value>::type>{
public:
// maybe specialize for non-int
};
template<typename T>
class A: public A_base<T>{
protected:
std::vector<T> my_vector;
};
This approach would be better than an empty function because you are being more strict about your API and better than a static_cast because it simply won't make it to the inside of the function (it won't exist) and will give you a nice error message at compile time (GCC shows "has no member named ‘only_for_ints’" on my machine).
The downside to this method would be compile time and code bloat, but I don't think it's too hefty.
(don't you dare say that C++11 requirement is a down-side, we're in 2014 god-damnit and the next standard has even be finalized already!)
Also, I noticed, you will probably have to define my_vector in the base class instead of the final because you probably want to handle that data within the member function.
A nice way to do that without duplicating a bunch of code is to create a base base class (good god) and inherit that class in the base class.
Example:
template<typename T>
class base_data{
protected:
std::vector<T> my_vector;
};
template<typename T>
class A_base<T, typename std::enable_if<std::is_integral<T>::value>::type>: public base_bata<T>{
public:
void only_for_ints(){/* phew, finally. fiddle around with my_vector! */}
};
// non-integer A-base
template<typename T>
class A: public A_base<T>{
protected:
// helper functions not available in base
};
That does leave a horrible looking multiple-inheritance scheme, but it is very workable and makes it easy to define members based on template parameters (for future proofing).
People often don't like multiple-inheritance or how complicated/messy SFINAE looks, but I couldn't live without it now that I know of it: the speed of static code with the polymorphism of dynamic code!
Not sure where I found this, but you can use = delete; as the function definition inside the class, thereby deleting the function for the general case, and then explicitly specialize outside the class:
template <typename T>
struct A
{
auto int_only(T) -> void = delete;
};
template <> auto A<int>::int_only(int) -> void {}
int main()
{
auto a_int = A<int>{};
auto a_dbl = A<double>{};
a_int.int_only(0);
// a_dbl.int_only(3.14); error: call to deleted member function
}
https://en.cppreference.com/w/cpp/language/function#Deleted_functions

What is the difference between 2 forms of specialization template implementation in c++

There are 2 different specialization template forms in c++
One is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
The other is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
They can also be compiled in VS2013. I notice that the second implementation of specialization template situation is just lack of template<>
I want to know what the difference is between the 2 forms above.
Visual C++ is wrong.
The standard is very clear about this.
First,
Members of an explicitly specialized class template are defined in the
same manner as members of normal classes, and not using the template<>
syntax.
Meaning that, for explicit specialization of a class template, the member definition strictly do not require template<>.
Example:
template<class T>
struct A {
};
template<>
struct A<int> {
void f(int);
};
// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { / ... / }
And,
A member or a member template of a class template may be explicitly
specialized for a given implicit instantiation of the class template,
even if the member or member template is defined in the class template
definition. An explicit specialization of a member or member template
is specified using the syntax for explicit specialization.
Meaning that, for a template that is not "explicit specialized", you can specialize its member, with the template<> (syntax for explicit specialization)
Example,
template<class T>
struct A {
void f(T);
};
// specialization
template<>
void A<int>::f(int);
The above examples are directly copied out from standard. To summarize, if the class is already explicitly specialized, do not use template<>, else if the class relies on implicit instantiation, use template<>.
Your first example compiles fine in Clang, and your second example fails to compile in Clang, you will get an error:
error: template specialization requires 'template<>'
template <class T> class mycontainer { ... };
template <> class mycontainer <char> { ... };
The first line is the generic template, and the second one is the specialization.
When we declare specializations for a template class, we must also define all its members, even those identical to the generic template class, because there is no "inheritance" of members from the generic template to the specialization.
http://www.cplusplus.com/doc/tutorial/templates/

C++ template gotchas

just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}

Difference between member functions for a template class defined inside and outside of the class

Is there a difference between defining member functions for a template class inside the class declaration versus outside?
Defined inside:
template <typename T>
class A
{
public:
void method()
{
//...
}
};
Defined outside:
template <typename T>
class B
{
public:
void method();
};
template <typename T>
void B<T>::method()
{
//...
}
For non-template classes, this is the difference between inlined and non-inlined methods. Is this also true for template classes?
The default for most of my colleagues is to provide definitions inside the class, but I've always preferred definitions outside the class. Is my preference justified?
Edit: Please assume all the above code is provided in the header file for the class.
Yes, the exact same is true for template classes.
The reason why method definitions for template classes are usually preferred to be inline is that with templates, the entire definition must be visible when the template is instantiated.
So if you put the function definition in some separate .cpp file, you'll get a linker error.
The only general solution is to make the function inline, either by defining it inside the class or outside with the inline keyword. but in either cases, it must be visible anywhere the function is called, which means it must typically be in the same header as the class definition.
There's no difference, aside from having to type more. That includes the template bit, the inline and having to use more "elaborate" names when referring to the class. For example
template <typename T> class A {
A method(A a) {
// whatever
}
};
template <typename T> inline A<T> A<T>::method(A a) {
// whatever
}
Note that when the method is defined inside you can always omit the template parameter list <T> when referring to A<T> and just use A. When defining it outside, you have to use the "full" name in the return type and in the name of the method (but not in the parameter list).
I know this..I think it must be some what help full to u?
defining a member function outside of its template
It is not ok to provide the definition of a member function of a template class like this:
// This might be in a header file:
template <typename T>
class xyz {
void foo();
};
// ...
// This might be later on in the header file:
void xyz<T>::foo() {
// generic definition of foo()
}
This is wrong for a few reasons. So is this:
void xyz<class T>::foo() {
// generic definition of foo()
}
The proper definition needs the template keyword and the same template arguments that the class template's definition was declared with. So that gives:
template <typename T>
void xyz<T>::foo() {
// generic definition of foo()
}
Note that there are other types of template directives, such as member templates, etc., and each takes on their own form. What's important is to know which you have so you know how to write each flavor. This is so especially since the error messages of some compilers may not be clear as to what is wrong. And of course, get a good and up to date book.
If you have a nested member template within a template:
template <typename T>
struct xyz {
// ...
template <typename U>
struct abc;
// ...
};
How do you define abc outside of xyz? This does not work:
template <typename U>
struct xyz::abc<U> { // Nope
// ...
};
nor does this:
template <typename T, typename U>
struct xyz<T>::abc<U> { // Nope
// ...
};
You would have to do this:
template <typename T>
template <typename U>
struct xyz<T>::abc {
// ...
};
Note that it's ...abc not ...abc<U> because abc is a "primary" template. IOWs, this is not good:
// not allowed here:
template template struct xyz::abc { };