c++ template partial specialization - c++

this might be question that someone asked before but i can't find it...
i have a class in a .hpp file :
class A{
public:
A(){//constructor}
~A(){//destructor}
//some public methods and arguments
template<typename Type>
void func(Type t){//do something for numbers}
private:
//some private methods and arguments
}
The template method should work for int, double... but not for string. Thus in my .hpp file, I defined what func does for numbers and in my .cpp file I wrote :
template<>
void A::func(std::string t){ // do something in that case}
But when I use the function func with std::string, the program calls the methods for numbers... So I replaced the .hpp file by :
class A{
public:
A(){//constructor}
~A(){//destructor}
//some public methods and arguments
template<typename Type>
void func(Type t){//do something for numbers}
void func(std::string s);
private:
//some private methods and arguments
}
and my .cpp file became :
void A::func(std::string t){ // do something in that case}
and then everything works !
my question is, is this the correct way to do that ?

That's not a partial specialization (there are no template parameters left un-specialized) it's an explicit specialization.
Templates must be visible to the code that uses them, if you don't declare the specialization in the header file then code that tries to call A::func with a string will instantiate the primary template (the one for numbers) and use that, because they don't know the `string specialization even exists.
So you must (at least) declare the specialization in the header in order for it to be usable outsde the .cpp file:
template<>
void A::func(std::string t);
However your alternative using an overload is simpler and is perfectly acceptable. It works because the overload for string is declared in the header, so code that calls it knows which function to call.

Overloading is a good approach for many purposes. However, I suspect your original template approach could be made to work too if you add a specialization for const char * as well. That way, you could pass in string literals without it resolving to the numbers version.

Related

Declaration doesn't solve 'explicit specialization after instantiation' error

Suppose I am attempting to create my own implementation of boost::filesystem::path, using the Curiously Recurring Template Pattern:
(Code is given incomplete for brevity, but will exhibit the problem as stated when compiled with 'g++ -std=c++11 -o mypath ./mypath.cpp', using GCC 4.8.4)
mypath.hpp:
#ifndef MYPATH_HPP
#define MYPATH_HPP
#include <string>
#include <vector>
namespace my {
template <class T>
class PathBase
{
public:
PathBase();
PathBase(std::string const& p);
std::string String() const;
bool IsSeparator(char c) const;
std::string Separators() const;
typedef std::vector<std::string> pathvec;
protected:
pathvec _path;
private:
virtual std::string _separators() const =0;
};
class Path : public PathBase<Path>
{
public:
Path();
Path(std::string const& p);
private:
virtual std::string _separators() const final;
};
} // namespace 'my'
#endif // MYPATH_HPP
mypath.cpp:
#include "mypath.hpp"
namespace my {
//////////template class PathBase<Path>;
template<>
bool PathBase<Path>::IsSeparator(char c) const
{
return (Separators().find(c) != std::string::npos);
}
template <>
std::string PathBase<Path>::Separators() const
{
return _separators();
}
} // namespace
int main(int argc, char** argv)
{
return 0;
}
Of course I discovered that the code as-written will not compile, since I explicitly specialize Separators() after IsSeparator() has implicitly instantiated it. But I don't particularly want to play whack-a-mole trying to keep all my methods favorably ordered.
While researching similar questions on SO, I found that this accepted answer to one of them suggested that I could solve this problem neatly by merely declaring my specialization. But...
My commented-out template class PathBase<Path>; line in mypath.cpp had no effect on the problem, and
It kinda feels like my header file already declares the explicit specialization with its entire class Path : public PathBase<Path> { ... } declaration.
Exactly what does my explicit declaration need to look like?
Let's get these out of the way first:
template class PathBase<Path>; does not declare an explicit specialization; it is an explicit instantiation definition. You're requesting that the compiler instantiate PathBase<Path> and all its members for which it has definitions, based on the definitions you provided up to that point. In this specific case, it doesn't make any difference indeed.
The declaration of an explicit specialization would look like template<> class PathBase<Path>;, but that's not what you want here either; see below.
The use of PathBase<Path> when defining Path doesn't declare an explicit specialization either; it triggers an implicit instantiation of PathBase<Path>, based on the definition you provided above. An implicit instantiation for a class template instantiates the class definition and only the declarations of its member functions; it doesn't try to instantiate the definitions of the functions; those are only instantiated when needed, later on.
In your cpp file, you're explicitly specializing IsSeparator and Separators for an implicitly instantiated PathBase<Path>. You're requesting that the compiler instantiate PathBase<Path> based on the generic definition you provided, but, when the definitions of those particular functions are needed, use the specific definitions you provide.
It's basically a shorthand alternative to explicitly specializing the whole class template, when the structure of the class and most of the generic definitions for the members are fine, and you only want to fine-tune the definitions of a few members. If you explicitly specialized the whole class template, you'd have to provide a separate class definition and definitions for all the member functions of the specialization, which would mean unnecessary copy-paste.
You need to tell the compiler about those explicit specializations as soon as possible, before there's any chance that some code would attempt to use the definitions (it needs to know that it will have to look for specific definitions instead of generic ones). You do that by declaring (not necessarily defining) the explicit specializations.
The safest place to do that is immediately after the closing brace of the definition of template <class T> class PathBase. Something like:
class Path;
template<> std::string PathBase<Path>::Separators() const;
template<> bool PathBase<Path>::IsSeparator(char c) const;
You definitely need to do this in the header file, not in a cpp file, otherwise other cpp files that use the header will not know about the explicit specializations and will try to instantiate generic versions (if they need them). That will make your program ill-formed, no diagnostic required (this applies to your example as well). What that means is: if the compiler is smart enough to diagnose the problem, you should be grateful; if it isn't, you can't complain, and it's still your fault.
Having declared the explicit specializations up front, the definitions can come later, possibly in a separate cpp file; that's fine, just like for normal functions.
Also note that, should you want to include the definitions for the explicit specializations in the header file (to ease inlining, for example), you'll have to declare them inline, again like for normal functions. Otherwise, including the header in multiple cpp files will make the program ill-formed, NDR (you'll typically get multiple definition errors at link time).
Obligatory standard quote from [temp.expl.spec]/7:
[...] When writing a specialization, be careful about its location; or
to make it compile will be such a trial as to kindle its
self-immolation.
Yes, the members of the standardization committee are human too.

C++ partial template specialization

Is this answer considered "good" code or is it just an ugly hack?
And I would like to know how this is forward-declared (both classes).
When I just forward-declare the class with 2 template-parameters, it just always takes this one, no matter what value flag has.
I would like to do this because I have 2 special member functions which should behave differently on flag being true and I don't feel like reimplementing the whole class. Also, it should have the same name. According to this example, this seems to be possible.
And I have to forward-declare it because I'm creating a library in which we forward-declare everything.
Any idea?
It has the drawback that it doesn't really work. The base member function is not overridden, but it is just hidden by the derived class' function when you try to call it from outside. Which means if you call doSomething out of the base class (where presumably all your other functions live) it will call the base class doSomething which is not what is wanted.
The accepted answer on that question shows multiple ways for how you can solve your problem.
In order to use specialisation its definition always has to be visible to the caller. If, for example, you have template <class Type, bool flag> struct something defined in one header and template <class Type> struct something<Type, true> : public something<Type, false> defined in the second one, to use the latter you have to include the second header. Without that you will always get the first, more generic type.
EDIT: the bit about forward-declaring got me thinking. If you want to use only type declaration, as in pointer variable, do the following:
Header
template <class Type, bool flag>
struct something;
struct Test
{
something<int, true>* ptr; // definition not needed
Test();
}
Source
#include "something.h" // header with template
#include "something_spec.h" // header with specialisation
Test::Test()
{
ptr = new something<int, true>(); // specialisation used
}

Linking problem when derived class calls a template function in base class

I have a class Base in base.h, which has a template function
class Base {
template <typename T> void test(T a);
}
this template is supposed to read in int or double type, and I have class Derived, which is derived from class Base
I tried to call function test in class Derived, but I have the linker error.
In the end, I realised that if in base.cpp, I add
void test(int a);
void test(double a);
there will be no compiler error. This solution seems awkward, is there a better solution? Thank you
C++ templates must be defined (given a complete function body) in the same translation unit (.CPP file plus all included header files) where they are used. In your header file, all you have done is declared (given the name and signature of) the function. The result is that when you include base.h, all the compiler sees is:
class Base {
template <typename T> void test(T a);
}
This declares but does not define the function. To define it, you must include a function body:
class Base {
template <typename T> void test(T a)
{
// do something cool with a here
}
}
The reason why this is required is that the C++ compiler generates code for templates on an "as-needed" basis. For example, if you call:
Base obj;
obj.test< int >( 1 );
obj.test< char >( 'c' );
The compiler will generate two sets of machine code based on the Base::test template, one for an int and one for a char. The limitation here is that the definition of the Base::test template must be in the same translation unit (.CPP file), or else the compiler will not know how to build the machine code for each version of the Base::test function. The compiler only operates on one translation unit at a time, so it has no idea whether or not you've defined Base::test< T > in some other CPP file. It can only work with what it has at hand.
This is quite different from the way generics work in C#, Java, and similar languages. Personally I like to think of templates as a text macro that gets expanded by the compiler as needed. That forces me to keep in mind that the complete body of the template function needs to be included in any CPP file where it is used.
You must fully define the template function test before it can be used. The easiest way to do that is just to write your function body in the header in base.h:
class Base {
template <typename T> void test(T a)
{
... function body here
}
}
if you declare template function in base class which means it take the template argument at compile time but if u try to access through derived class which is runtime implementation so template request at compile time which ur providing at runtime is not possible ,and main thing c++ does not support this.

Template specialization of a single method from a templated class

Always considering that the following header, containing my templated class, is included in at least two .CPP files, this code compiles correctly:
template <class T>
class TClass
{
public:
void doSomething(std::vector<T> * v);
};
template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
// Do something with a vector of a generic T
}
template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
// Do something with a vector of int's
}
But note the inline in the specialization method. It is required to avoid a linker error (in VS2008 is LNK2005) due to the method being defined more then once. I understand this because AFAIK a full template specialization is the same as a simple method definition.
So, how do I remove that inline? The code should not be duplicated in every use of it. I've searched Google, read some questions here in SO and tried many of the suggested solutions but none successfully built (at least not in VS 2008).
Thanks!
As with simple functions you can use declaration and implementation.
Put in your header declaration:
template <>
void TClass<int>::doSomething(std::vector<int> * v);
and put implementation into one of your cpp-files:
template <>
void TClass<int>::doSomething(std::vector<int> * v) {
// Do somtehing with a vector of int's
}
Don't forget to remove inline (I forgot and thought this solution will not work :) ).
Checked on VC++2005
You need to move specialization definition to CPP file.
Specialization of member function of template class is allowed even if function is not declared as template.
There is no reason to remove the keyword inline.
It does not change the meaning of the code in anyway.
If you want to remove the inline for whatever reason the solution of maxim1000 is perfectly valid.
In your comment, though, it seems you believe that the inline keyword means that the function with all his contents gets always inlined but AFAIK that is actually very much dependent on your compiler optimization.
Quoting from the C++ FAQ
There are several ways to designate that a function is inline, some of
which involve the inline keyword, others do not. No matter how you
designate a function as inline, it is a request that the compiler is
allowed to ignore: the compiler might inline-expand some, all, or none
of the places where you call a function designated as inline. (Don’t
get discouraged if that seems hopelessly vague. The flexibility of the
above is actually a huge advantage: it lets the compiler treat large
functions differently from small ones, plus it lets the compiler
generate code that is easy to debug if you select the right compiler
options.)
So, unless you know that that function will actually bloat your executable or unless you want to remove it from the template definition header for other reasons, you can actually leave it where it is without any harm
This is a little OT, but I thought I'd leave this here in case it helps someone else. I was googling about template specialization which led me here, and while #maxim1000's answer is correct and ultimately helped me figure my problems out, I didn't think it was abundantly clear.
My situation is a little different (but similar enough to leave this answer I think) than the OP's. Basically, I'm using a third party library with all different kinds of classes that define "status types". The heart of these types are simply enums, but the classes all inherit from a common (abstract) parent and provide different utility functions, such as operator overloading and a static toString(enum type) function. Each status enum is different from one another and unrelated. For example, one enum has the fields NORMAL, DEGRADED, INOPERABLE, another has AVAILBLE, PENDING, MISSING, etc. My software is in charge of managing different types of statuses for different components. It came about that I wanted to utilize the toString functions for these enum classes, but since they're abstract I couldn't instantiate them directly. I could have extended each class I wanted to use, but ultimately I decided to create a template class, where the typename would be whatever concrete status enum I cared about. Probably some debate can be had about that decision, but I felt like that was a lot less work than extending each abstract enum class with a custom one of my own and implementing the abstract functions. And of course in my code, I just wanted to be able to call .toString(enum type) and have it print the string representation of that enum. Since all the enums were entirely unrelated, they each had their own toString functions that (after some research I learned) had to be called using template specialization. That led me here. Below is an MCVE of what I had to do in order to make this work correctly. And actually my solution was a bit different than #maxim1000's.
This is a (greatly simplified) header file for the enums. In reality, each enum class was defined in it's own file. This file represents the header files that are supplied to me as part of the library I am using:
// file enums.h
#include <string>
class Enum1
{
public:
enum EnumerationItem
{
BEARS1,
BEARS2,
BEARS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
class Enum2
{
public:
enum EnumerationItem
{
TIGERS1,
TIGERS2,
TIGERS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
adding this line just to separate the next file into a different code block:
// file TemplateExample.h
#include <string>
template <typename T>
class TemplateExample
{
public:
TemplateExample(T t);
virtual ~TemplateExample();
// this is the function I was most concerned about. Unlike #maxim1000's
// answer where (s)he declared it outside the class with full template
// parameters, I was able to keep mine declared in the class just like
// this
std::string toString();
private:
T type_;
};
template <typename T>
TemplateExample<T>::TemplateExample(T t)
: type_(t)
{
}
template <typename T>
TemplateExample<T>::~TemplateExample()
{
}
next file
// file TemplateExample.cpp
#include <string>
#include "enums.h"
#include "TemplateExample.h"
// for each enum type, I specify a different toString method, and the
// correct one gets called when I call it on that type.
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
return Enum1::toString(type_);
}
template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
return Enum2::toString(type_);
}
next file
// and finally, main.cpp
#include <iostream>
#include "TemplateExample.h"
#include "enums.h"
int main()
{
TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1);
TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3);
std::cout << t1.toString() << std::endl;
std::cout << t2.toString() << std::endl;
return 0;
}
and this outputs:
BEARS1
TIGERS3
No clue if this is the ideal solution to solve my problem, but it worked for me. Now, no matter how many enumeration types I end up using, all I have to do is add a few lines for the toString method in the .cpp file, and I can use the libraries already-defined toString method without implementing it myself and without extending each enum class I want to use.
I'd like to add that there is still a good reason to keep the inline keyword there if you intend to leave also the specialization in the header file.
"Intuitively, when you fully specialize something, it doesn't depend on a template parameter any more -- so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule..."
Reference: https://stackoverflow.com/a/4445772/1294184

Is it possible to have a non-template class subclass a template class?

I have a template class defined like so:
template <class T>
class Command {
public:
virtual T HandleSuccess(std::string response) = 0;
virtual std::string FullCommand() const = 0;
// ... other methods here ...
};
Will C++ allow me to create a non-template subclass of a template class? What I mean is can I do something like this:
class NoopCommand : public Command<NoopResult> {
public:
NoopResult HandleSuccess(std::string response);
std::string FullCommand() const;
// ... other methods here ...
};
As is that is not working for me because it says the following virtual functions are undefined:
T admix::Command<T>::HandleSuccess(std::string) [with T = admix::NoopResult]
std::string admix::Command<T>::FullCommand() const [with T = admix::NoopResult]
How can I specifically define them for the given T?
As we figured out in IRC, that was because you have
Made your functions non-pure
Sliced the derived object part. So the base class functions were called because the object wasn't a complete derived object anymore.
(Below follows my suspicion on earlier versions of your question - i keep it for further consideration and to keep the comments meaningful)
I think the issue here is that the compiler is free to instantiate any virtual function member of a class template even if it's not used (i.e not called). Instantiating a function will need a function definition to be provided. Try to add this in the header, where the compiler will find them and instantiate a definition from:
template<typename T>
T Command<T>::HandleSuccess(std::string response) { /* put some default action ... */ }
template<typename T>
std::string Command<T>::FullCommand() const { /* put some default action ... */ }
C++ Standard 14.7.1/9:
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual
member function, a member class or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.
"virtual functions are undefined" means you have not defined the function bodies of NoopCommand::HandleSuccess and NoopCommand::FullCommand.
The following should solve your problem.
class NoopCommand : public Command<NoopResult> {
public:
NoopResult HandleSuccess(std::string response) {}
std::string FullCommand() const {}
// ... other methods here ...
};
Or you you have a NoopCommand.cpp, make sure it's included in your build process.
The pattern you use is widely known as the "Curiously Recurring Template Pattern". so, yes, you can do that.
I can't think of a reason why it does not compile.
The code you gave compiles for me, without errors (after adding a struct NoopResult { };). Maybe there's a problem in the code you left out?
litb found the solution on ##c++ last night.
The issue was I was passing a NoopCommand to a function like this:
void SendCommand(Command<T> command);
When I should have made the signature this:
void SendCommand(Command<T>& command);
Making that change allows everything to compile.