I have written two different container classes, which have the same interface but use different member data and algorithms to operate on their members. I also have a template function that takes a container and does some useful calculation:
class Container1
{
// implementation here
};
class Container2
{
// implementation here
};
template<typename ContainerType>
void my_function(ContainerType const& container, /* other parameters */)
{
// ...
}
What bothers me is the fact that 'my_function' should only accept Container1 or Container2, but this is not expressed by the code, since ContainerType can be any type. The function is templated by container type since it does the same thing no matter what is the internal implemetation of container.
I am considering a variant where Container1 and Container2 would be full specializations of a template class. Then I could be more specific about the argument of my_function:
template<typename T>
class Container;
// Tags to mark different container types
struct ContainerType1 { };
struct ContainerType2 { };
template<>
class Container<ContainerType1>
{
// implementation
};
template<>
class Container<ContainerType2>
{
// implementation
};
template<typename T>
void my_function(Container<T> const& container, /* other parameters */)
{
}
In the first case, the compilation with a wrong template parameter will fail if 'ContainerType' does not have the interface required by my_function, which is not very informative. In the second case, I would also get a compiler error (failed template parameter deduction) if I supply anything else than Container<ContainerType1> or Container<ContainerType2>, but I like it better since it provides a hint about what kind of template parameter is expected.
What are you thoughts about this? Is it a good design idea or not? Do you think it is worth the change in the code? There are many other functions like my_function in the code and sometimes it is not obvious what kind of template parameters they expect. What are my other options to make my_function more specific? I am aware the existence of Boost Concept Check Library.
For the sake of argument, let's suppose that I don't want to solve the problem by using inheritance and virtual functions.
In case it is relevant to the discussion, the common interface of Container1 and Container2 is imposed by using CRTP. There might be more container classes in the future.
There are a few solutions to this kind of problem.
Your solution (implementing your types as a template specialization) is one, but one I don't particularly like.
Another is the CRTP:
template<typename T>
struct Container {
// optional, but I find it helpeful
T* self() { return static_cast<T*>(this); }
T const* self() const { return static_cast<T const*>(this); }
// common code between every implementation goes here. It accesses itself through self(), never this
};
class ContainerType1: public Container<ContainerType1> {
// more details
};
class ContainerType2: public Container<ContainerType2> {
// more details
};
that is the core of the CRTP.
Then:
template<typename T>
void my_function(Container<T> const& container_, /* other parameters */)
{
T const& container = *(container.self());
}
and bob is your uncle. As a bonus, this provides a place to put common code.
Another option is a tag traits class that marks the types you want to support, like iterator_traits.
template<typename T>
struct is_container : std::false_type {};
template<>
struct is_container<ContainerType1> : std::true_type {};
template<>
struct is_container<ContainerType2> : std::true_type {};
you can even do SFINAE style pattern matching to detect a base type (like how iterators work).
Now your method can test on is_container<T>::value, or do tag dispatching on is_container<T>{}.
I think your first version is do-able.
At the end of the day, you always have to choose the optimum approach. Second one may look like an overkill although it gets the point across.
If you Container classes will both have a common function (let's say Container1::hasPackage() or Container2::hasPackage() and you choose to call it within my_function then it straight away puts your point across that the eligibility to call it is that function itself. After going through many such projects you will start reading the templates in a reverse manner - starting from the template definition - to see what least properties are needed qualify a particular class.
Having said all this, perhaps your question was more suited for Code Review
One example I created on ideone was using your classes but adding a member variable name to them both which is expected by my_function. Of course there may be classes that will support name but the developer may also burn his fingers a few times to realize the idea behind the function.
Related
It seems understanding template template parameters will kill me :(, Let me explain what misconception I made in my mind which confuses me:
template<class T>
class B {}; // A templated class
Here is other code:
template<template<class X> class Z = B> // The problem is in this line for me
class BB{};
Note the line in the parameter list of templated class BB, which is:
template<class X> class Z = B
Now, what stops C++ to think that Z is not another templated class Z?
I.e.,
template<class X> class Z {
}
rather than thinking class Z is a templated parameter itself.
Mankarse has answered your question, but I thought I'd chime in anyway.
Template template parameters are just like normal template type parameters, except that they match templates instead of concrete types:
// Simple template class
template <typename Type>
class Foo
{
Type m_member;
};
// Template template class
template <template <typename Type> class TemplateType>
class Bar
{
TemplateType<int> m_ints;
};
If it helps, you can kind of think of them as like function pointers. Normal functions just accept arguments like normal templates just accept types. However, some functions accept function pointers which accept arguments, just like template template types accept templates that accept types:
void foo(int x)
{
cout << x << endl;
}
void bar(void (*f)(int))
{
f(1);
f(2);
}
To answer your question in the comments: template template template parameters are not possible. However, the reason they are not possible is just because the standardisation committee decided that template templates were enough, probably to make lives easier for the compiler implementors. That being said, there's nothing stopping the committee from deciding that they are possible, then things like this would be valid C++:
template <template <template <typename> class> class TemplateTemplateType>
class Baz
{
TemplateTemplateType<Foo> m_foos;
};
typedef Baz<Bar> Example;
// Example would then have Bar<Foo> m_foos;
// which would have Foo<int> m_ints;
Again, you can see parallels in function pointers.
types <=> values
templates <=> functions of values
template templates <=> functions of functions of values
template template templates <=> functions of functions of functions of values
The analogous function to Baz would be:
void baz(void (*g)(void (*f)(int)))
{
g(foo);
}
Where would you use a template template template?
It's pretty far-fetched but I can think of one example: a really generic graph searching library.
Two common algorithms in graph searching are the depth-first search (DFS) and the breadth-first search (BFS). The implementation of the two algorithms is identical except in one regard: DFS uses a stack of nodes whereas BFS uses a queue. Ideally, we'd just write the algorithm once, with the stack/queue as an argument. Also, we'd want to specify the implementation container of the stack or queue, so that we could do something like:
search<Stack, Vector>( myGraph ); // DFS
search<Queue, Deque>( myGraph ); // BFS
But what is a Stack or a Queue? Well, just like in the STL a stack or a queue can be implemented with any kind of container: vectors, deques, lists etc. and could also be stacks of any element type, so our stacks or queues would have the interface:
Stack<Vector, int> // stack of ints, using a vector implementation
Queue<Deque, bool> // queue of bools, using a deque implementation
But Vector and Deque themselves are template types!
So finally, our Stack would be a template template like:
template <template <typename> class Storage, typename Element>
struct Stack
{
void push(const Element& e) { m_storage.push_back(e); }
void pop() { m_storage.pop_back(); }
Storage<Element> m_storage;
};
And our search algorithm would then have to be a template template template!
template <template <template <typename> class, typename> class DataStructure,
template <typename> class Storage,
typename Graph>
void search(const Graph& g)
{
DataStructure<Storage, typename Graph::Node> data;
// do algorithm
}
That would be pretty intense, but hopefully you get the idea.
Remember: template template templates are not legal C++, so this whole graph search thing won't actually compile. It's just a "what if?" :)
This is part of the syntax of the language (which is monstrous and massively context-dependent). If template<class X> class Z occurs in a template-parameter-list then it is interpreted as declaration of a formal parameter Z with the kind (like a meta-type; kinds classify types in the same way types classify values) "template class taking one class argument".
The usage examples in the accepted answer are misleading,
especially for beginners. Granted it's hard to come up with anything that won't be contrived, but we should at least contrive something that doesn't contradict the overall principles. Template parameters should be used only when the user of our interface can't specify the type of the template for one or the other reason, and we need to do it for them. In the Stack example we ask for both Storage and Element, only to instantiate Storage with that very Element, which is entirely unnecessary, the user can easily perform a basic substitution:
Stack<deque<int>> my_stack;
And all the stack needs to do is this:
template <typename Storage>
struct Stack
{
void push(typename Storage::const_reference e) { m_storage.push_back(e); }
void pop() { m_storage.pop_back(); }
Storage m_storage;
typename Storage::reference top() { return m_storage.back(); }
};
It doesn't in any way decide for the user what the element type is, so it does not need the template parameter. Hence the search becomes
template <template <typename> class DataStructure,
template <typename> class Storage,
typename Graph>
void search(const Graph& g, typename Graph::const_reference)
{
DataStructure<Storage<typename Graph::Node>> data;
// do algorithm
}
Here I guess we assume that internal Graph::Node type is not accessible to the user, and search is somehow a friend function of the Graph, which seems to make some sense. However, do we actually need to fill the structure with graph nodes, or simply references to them? Can the user not refer to the nodes in any way? If not, why is it called a graph, and not, say, slow_unordered_set? So lets imagine for a second they have an access to some node reference/pointer type, then they can do this:
search<Stack<vector<Graph::node_ptr>>>(graph, 10);
The function simplifies further to this:
template <typename StackStructure, typename Graph>
void search(const Graph& g, typename Graph::const_reference)
{
StackStructure data;
// do algorithm
}
Gosh darn it, now it's more generic than ever! Do you want to specify an allocator for the storage? No problem, just do it. You instead wanted some statically allocated vector that requires maximum size parameter? Go right ahead. Want to implement the stack from scratch altogether? Well, as long as it quacks like a stack...
Perhaps a more appropriate example
of a template with template parameters would be some class that represents a complex system and uses some Storage template for a bunch of internal structures, and for some reason is parameterized on that Storage template:
template <template <typename> class Storage>
class System
{
Storage<Component_1> components_1;
Storage<Component_2> components_2;
Storage<Component_3> components_3;
Storage<MetaInfo> registry;
public:
// some inane interface
};
If you ask me - this code reeks, but it's not like I wouldn't write it.
Now that we have this semi-appropriate example for a template with a template parameter, we can contrive something for a template with a template parameter that itself has a template parameter: Imagine somehow we end up with like 10 of these System classes that all have the same interface, all parameterized on a Storage template, but otherwise very VERY different. Brace yourselves for the SuperSystem, an even more complicated class, that uses a bunch of our systems, but CRUCIALLY needs to decide itself what Storage templates to use with each system.
template< template< template <typename> class Storage> class System>
class SuperSystem
{
System<Vector> system_1;
System<OtherVector> system_2;
System<List> system_3;
public:
// absolutely bonkers interface
};
We want to specify something down the template hierarchy we're dealing with here, but still leave something up the hierarchy customizable. For some reason we don't know what exact system we will be dealing with, but we know something very specific about all of them, that we absolutely need to go our way. This is an overarching theme with these examples, our goal is not to make things more generic and customizable, but the opposite - we want to lock down certain deeply embedded things.
TL;DR
In my experience you would only encounter good use cases for templates with template parameters when knee deep in a meta programming library. A rule of thumb: if you can recognize this pattern
template<...> struct f { typedef ... type; };
as a type function, then in that mindset you are allowed to use templates with template parameters, and maybe ponder about anything deeper. Otherwise slap yourself on the wrist.
Consider this code:
template<typename T, SomeEnum mode> struct TC{
T data;
//...
void doStuff();
};
can "doStuff" have more than one definitions based on the the enum value set for the template?
TC<int, SomeEnum::MODE_1> tc1; tc.doStuff(); //do some stuff
TC<int, SomeEnum::MODE_2> tc2; tc.doStuff(); //do some other stuff
(I don't mean save "mode" and make a branch on it but actually multiple definitions.)
You can do tag dispatch. Just provide an overload for each packaged value of the enum:
template<typename T, SomeEnum mode> struct TC{
T data;
//...
template<SomeEnum v>
using tag_type = std::integral_constant<SomeEnum, v>;
void reallyDoStuff(tag_type<SomeEnum::MODE_1>);
void reallyDoStuff(tag_type<SomeEnum::MODE_2>);
void doStuff() { reallyDoStuff(tag_type<mode>{}); }
};
Because the member functions of a class template won't be instantiated unless used, you'd only instantiate one definition of reallyDoStuff (the proper one) for every instance of TC.
When in doubt, prefer function template overloading to specialization. It's usually the superior alternative.
This is, in general, what template specialization is for. If you don't know what template specializations are, you need to read your C++ book first, before reading the rest of my answer.
The only stumbling block here is that individual class methods cannot be specialized, the entire class must be specialized. But there are common approaches around that, such as the following.
Define your member function as just a function call wrapper to a helper template class, like this:
template<typename T, SomeEnum mode> void TC::doStuff()
{
doStuff_helper<T, mode>::doStuff(*this);
}
That's your actual doStuff(). The actual code goes into the helper class.
Define the helper class template as follows (you will need to properly use forward declarations, and other such miscellanea, of course):
template<typename T, SomeEnum mode> class doStuff_helper {
public:
static void doStuff(TC<T, mode> &me)
{
// ...
}
};
Everything that your original class method did, can now be done here, with some obvious differences. This not the actual method of the original class, any more. So, instead of the original this, you have the me reference here to use. And because this is not the actual class method, there will be the usual issues with accessing private or protected class members. But these are minor details that are easily solved on their own merits. The point is that what you can do now, is specialize the whole thing:
template<typename T> class doStuff_helper<T, MODE_VALUE> {
public:
static void doStuff(TC<T, MODE_VALUE> &me)
{
// ...
}
};
This doStuff() can now be something completely different. This is the general approach for turning class methods specializations, which are not allowed, into ordinary, garden variety, class specialization.
There are further refinements on this general approach that are frequently used. One such refinement would be to have this factored out doStuff() itself be nothing more than a wrapper and a method call to me, with the general and the specialized versions invoking different methods in the original template class.
Once you then work out what happens here, with a piece of paper and a pencil, you will discover that what it ends up doing is turning a single call to the original doStuff() class method into calling two different class methods (which would typically be private), depending on the parameter to the original template class. And those two different class methods would essentially be your two different versions of doStuff() that you wanted to have originally, with only the appropriate method being used depending on the template parameter.
I have stumbled many times on classes defined like
class PureVirtualClass
{
virtual int foo() = 0;
virtual bool bar() = 0;
}
template <class T> class ImplClass : public virtual PureVirtualClass
{
virtual ~ImplClass(){};
int foo() { return 42;}
bool bar() { return true;}
//several other method having nothing to do with T
}
This "design" appears so often I want to think the original developer knew what he was doing by defining ImplClass as template class but without any reference to the template argument T anywhere. My own c++ template knowledge is kinda limited.
Is there a benefit to this or is it just a confused programmer?
There can be a benefit for classes being templated but not depending on the argument. Most often you see such things to define (empty) tag-structures for template metaprogramming:
template <class X>
struct some_tag {};
The benefit of classes like yours in general is that while you have the same functionality in each class, they are different classes and you can't copy one into the other, i.e. an object of type ImplClass<int> is not compatible with another object of type ImplCalss<float>.
There are many useful cases of the idea mentioned by Arne. For instance, looking at Very basic tuple implementation, this is how a single tuple element is defined:
template <size_t N, typename T>
class TupleElem
{
T elem;
public:
T& get() { return elem; }
const T& get() const { return elem; }
};
It is templated on N, without depending on it. Why? Because the tuple implementation
template <size_t... N, typename... T>
class TupleImpl <sizes <N...>, T...> : TupleElem <N, T>...
{
//..
};
derives multiple such elements, each with a unique N, serving as an identifier. Without it, TupleImpl would be deriving the same class twice, had two element types been identical within parameter pack T.... Neither random access to elements would work in this case (via an explicit call of function get() of the appropriate TupleElem base class, which would be ambiguous), nor empty base optimization (via specializing TupleElem for empty types T to not have a data member of type T).
This is a real use case, and exactly how std::tuple is implemented by clang. Of course, a class like TupleElem would be a hidden implementation detail, and not part of the interface. For instance, gcc follows an entirely different recursive class design.
In general, you will need to study the context where classes are used to understand the intent of the designer.
maybe that developer simply is too lazy to split the classes into .h and .cpp files?
Without using templates, linker errors would occur if the classes are used in multiple compilations units. When using templates, the linker usually discards duplicate instantiations of a template at link time (or handles the problem in a different way).
While this may be an answer to "why did the developer do this", I would not recommend this if the question was "when should I introduce template arguments which are never used" (see the other answers for this). Even though it is annoying to split code into .h and .cpp (especially when used to languages like Java or C#), it's the usual C++ way. And it is definitely easier to read/understand than using templates only for this purpose. Also, it makes the use of the classes less readable.
I'm not familiar with C++0x. I just started learning C++ myself about 6 months ago, I have a fairly strong grasp though (for a beginner).
I have a templated class:
template <typename T>
class Node
{
...
}
Then later, I have this:
template <typename T>
class BinaryTree
{
protected:
typedef Node<T>* node_t;
...
}
Here, the Binary tree class is serving as a "base class" that can be extended by specializations of binary trees. (AVL Tree, Red-Black, etc.,) The node typedef is protected, because the idea is the specializations will be able to use it...and they can, but it looks pretty awful.
For example, in my BiTree class (my creative name for the most generic binary tree, basically a BST), we have this:
template <typename T>
class BiTree : public BinaryTree<T>
{
private:
typedef typename BinaryTree<T>::node_t node_t; // Yuck
...
}
To make matters worse, I'm one of those people who likes to specify functions outside of a class, so when I want to say node_t is the return type...well, have a look...
template <typename T>
typename BiTree<T>::node_t
BiTree<T>::insert(BiTree<T>::node_t& node, T data)
{
...
}
Is there a way to just use node_t? That was sort of the whole point of inheriting the typedef from the base class. Is this what the using keyword in C++0x is for? How would I apply it to this situation? Thanks.
EDIT: The reason I'm wondering if it's useful is because of this question: C++ template typedef
The answer to your question is no, it isn't applicable. using in the context you mean is intended for renaming a templated type while retaining its templated nature. You have a specific instance of the template in mind, so it is not appropriate.
However, part of your concern seems to simply be the overabundance of BiTree<T>:: in your function definition. It doesn't seem that bad to me; you get used to seeing constructs like that. But it can be reduced if you want.
What you started with:
template <typename T>
typename BiTree<T>::node_t BiTree<T>::insert(BiTree<T>::node_t& node, T data)
{ ... }
First of all, once you name the function, you're already "inside" the class BiTree<T>, so the compiler will look inside it for types of your arguments.
template <typename T>
typename BiTree<T>::node_t BiTree<T>::insert(node_t& node, T data)
{ ... }
Another new feature of C++0x is the ability to wait to declare the result of a function until after you declare its arguments. It is intended for use in situations where the type of the result depends on the types of the arguments, but it is useful here as well for the same reason as above. The compiler will consider types within BiTree<T> when analyzing it:
template<typename T>
auto BiTree<T>::insert(node_t& node, T data) -> node_t
{ ... }
Almost no repetition. You can technically go one step further:
template<typename T>
auto BiTree<T>::insert(node_t& node, T data)
-> std::remove_reference<decltype(node)>::type
{ ... }
Now, you don't even repeat the parameter type, but getting the return type correct is notably more difficult [as evidenced by the fact that I got it wrong initially ;-)].
Ehm... base class typedefs are available in the derived class without any hocus pocus, just use node_t (though _t is a bad suffix, as all names ending in it are reserved by the POSIX standard). But I'm wondering, why do you make it protected / private if you want to return such a node from insert ? How should that be used, as nobody outside of the class hierarchy can use the node_t?
I have the following struct:
template <typename T>
struct Odp
{
T m_t;
};
I want to specialize it so I can add an operator so the type plays nicely with STL sets. (I can't modify Odp directly; it's legacy code.) Here are two methods I see of doing it:
struct Ftw : public Odp<int>
{
bool operator==(const Ftw& rhs)
{
return m_t == rhs.m_t;
}
};
struct FtwContain
{
Odp<int> odp;
bool operator==(const FtwContain& rhs)
{
return odp.m_t == rhs.odp.m_t;
}
};
Is there any reason to prefer the second over the first? The first method appears to allow cleaner code:
Ftw ftw;
ftw.m_t = 2;
FtwContain ftwContain;
ftwContain.odp.m_t = 2;
(Also, there's a chance that I'm confused about what the term "template specialization" means.)
I don't believe there is any need to create a new type - simply write a free function:
template <typename T>
bool operator==( const Odp<T> & a, const Odp <T> & b ) {
return a.m_t == b.m_t;
}
You may indeed be confused about the terminilogy. (Partial) template specialization normally referes to a specific implementation of a templated class /struct for a dedicated type. I.e. you may have a generic template class Hash that provides hash values for types using a method getHash. This method then has a generic implementation, that doesn't care about the type, and maybe a special implementation for hash values on strings:
// default implementation
template<typename T> class Hash { int getHash(T val) { return val; } }
// string implementation
template<> class Hash<std::string> { int getHash(std::string val) { return val[0] || val[1]; } }
What you are doing in ur examples however is not template specialization but inheritance (in the first approach) and using the Odp template as a client. In both cases, if anyone uses the Odp template as in Odp<int> odp, the original implementation will be used, which may not be what you want. If you would use proper template specialization, Odp<int> would refer to your specialized code.
Why not deriving Odp to MyOdp, put your (generic) code in it and just make Ftw derive from Odp (as in your first example) or using a typedef ?
By the way that not specialization but instanciation. Template specialization is when you (re)define a method for a specific type.
I usually prefer composition over inheritance, but it really depends on the design. Is Ftw a type of Odp or does Ftw contain an Odp.
I wouldn't choose the method based on cleaner code (since it's not that much of a difference), I would choose the method based on conceptually what is the relationship between Odp and Ftw.
In the case you mentioned, I think a free function is possibly the cleanest way with the least amount of rebuild issues. Put this free function in a separate cpp file and you should be good to go.
Possible cases for derivation
You would want to derive if you have to pass your object to some function which takes a base-class type
Is the derived class a type of the first type. If so, yes (eg., a carnivore is an animal)
3.If there are protected methods in the base class that you want to use in your derived class. I am not sure if the structure you mentioned is the complete code or only the relevant section. If it is not, then this might be one reason you want to derive.
Possible cases for containing
You merely want to use the class and there is no is-a relationship. TBH, one can simulate an is-a with containing objects too, where in the container type acts like a proxy for the contained-type (I think this is a design pattern, but am not sure of the name of the pattern).
You are interested in using only one or two methods, and there is no worry of a shared state
This object is never passed to any other interface which requires a base class (one can always pass the contained object, but that looks dirty. Also, toss in virtual functions and things are different. Sorry, I digress).
As Neil mentions, operator== can well be a free function.
Another option: standard library allows the use of custom predicate objects. In this case:
#include <set>
template <typename T>
struct Odp
{
T m_t;
};
struct CompareOdp
{
template <class T>
bool operator() (const Odp<T>& a, const Odp<T>& b) const
{
return a.m_t < b.m_t;
}
};
int main()
{
std::set<Odp<int>, CompareOdp > my_set;
Odp<int> value = {10};
my_set.find(value);
}
(Not sure, whether it might be a better idea to make the whole predicate a template. Making just operator() a template seems to make it easier to use, as it leaves more things to the compiler to figure out. Not sure if it could back-fire in some scenarios.)
Also note that std::set uses a predicate for ordering (by default std::less<X>), not for equality tests.