The following compiles in GCC:
cvec.hpp:
template <class T>
class cvec : public deque<T>
{
class deque<T>::iterator Find(T);
};
cvec.cpp:
template <class T>
class deque<T>::iterator cvec<T>::Find(T element)
{
}
In Visual C++, get:
error C2242 "typedef name cannot follow class/struct/union.
I changed "class" in the header file to "typename", but receive error C3860 - template argument list must list parameters in the order used in the template param list. There is only one parameter in this case, T. Unless the compiler is confused about Find(T element)?
What is this supposed to mean in the header:
class deque<T>::iterator Find(T);
You are not declaring a class. The typename keyword would be valid here, but class makes no sense.
And the same is true in the .cpp file:
template <class T>
typename deque<T>::iterator cvec<T>::Find(T element)
is correct, class isn't.
Apart from this, it really looks like what you're trying to do is a horrible idea. std::deque already has a find function. It works. It is correct. It is efficient. There is no need to reinvent it.
The standard library containers are also not designed to be derived from. They don't have virtual destructors.
All you're achieving (apart from the compile errors) is that you're going to end up with a buggy, less efficient container class that'll confuse other C++ programmers because it doesn't use the idiomatic interface.
This should really be a comment, but I'm making it an answer so that I can format it for readability.
#jalf and #dvl -- As #dvl said above, none of the std containers have virtual destructors. Why does that matter?
Let's say you derive a class "X" from from std::deque.
class X : public std::deque<int>
{
// whatever ...
};
Let's now say that you have an "X" object, pointed to by a base pointer.
std::deque<int> *p = new X;
and you delete it
delete p;
The destructor for the derived class X will not be called, which can lead to lots of problems.
Your options:
1. Don't derive from std containers. Make them data members and write wrappers to expose the functionality.
2. Only derive from std containers if the derived class has no destructor and no data members with destructors.
3. If you derive from a std container, never refer to it by a base pointer.
After you create a class, it is sometimes hard to know how the class might be used in the future. For that reason, many developers stick strictly to option "1". Personally I permit deriving from a std container as long as it is well documented and used with care.
This works for me in 2010:
#include <deque>
template <class T>
class cvec : public std::deque<T>
{
public:
typedef typename std::deque<T>::iterator iterator;
iterator Find(T element);
};
template <class T>
typename cvec<T>::iterator cvec<T>::Find(T element)
{
return std::deque<T>::iterator();
}
using namespace std;
int main()
{
cvec<int> c;
c.Find(1);
return 0;
}
Related
Say I have a template class:
template <typename T> class StringDeque:
public std::deque<T>
{
public:
...
private:
typedef std::deque<T> BaseClass;
};
Say I want to create concrete class ArrayString where T=std::string.
What is the proper way to achieve that:
define
#define ArrayString StringDeque<string>
typedef
typedef StringDeque < string > ArrayString;
inheritance
class ArrayString :
public StringDeque < string > {};
I'm not sure whether all of the suggestions are valid. Anyway I'm trying to figure out which practice most fits.
You want to give a name to a particular type (which happens to be an instantiation of a template). The C++ way to give names (aliases) to types is with a typedef:
typedef StringDeque<string> ArrayString;
Or, since C++11, with an alias declaration:
using ArrayString = StringDeque<string>;
Side note: when thinking about this stuff, it generally helps to think in terms of the correct template terminology. You don't have a "template class" (a class with special properties), you have a "class template" (a template for creating classes). The template is not a type; its instantiations are.
Proper ways:
typedef std::deque<std::string> StringDeque;
using StringDeque = std::deque<string>;
That said, here are some more notes on your question:
You wrote:
template <typename T> class StringDeque: public std::deque<T> // ...
std container classes are not meant as base classes. This means they should not be inherited from (and inheriting from them is UB).
When you want to use std container functionality in another class, the answer should always be encapsulation. That means, the correct way to build on the functionality of std::queue in your classes is:
template<typename T> class StringDequeue {
std::deque<T> storage;
public:
// add interface here that uses storage
};
You also proposed this:
#define ArrayString StringDeque<string>
Please never use define to declare a type. It works, but it has it's own pitfalls and is considered bad practice in C++.
Create type aliases with typedef or (since C++11) using:
typedef StringDeque<std::string> ArrayString;
using ArrayString = StringDeque<std::string>;
The preprocessor is a sledgehammer: occasionally useful but, with no knowledge of language-level constructs, prone to break code in surprising ways. In this case, I think the only problem is that the name won't be constrained to any scope; but that's reason enough to avoid it.
Inheritance creates a new type; while it's usually usable where the base type is, it's not completely interchangable, and doesn't inherit any constructors from the base type. So that's also not what you want for a simple type alias.
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.
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?
Initially I was trying to typedef a template class and I got to the "gotw 79" article.
And I didn't want to create another class so I ended up doing the following. Basically typedef'ing inside the same class. It works obviously. but is it a good practice?
template <typename T,typename L>
class MyClass{
typedef std::tr1::shared_ptr<MyClass<T,L> > shrdPtr;
}
Thank you.
Well, I'm not a big fan of it unless you are designing MyClass to be specifically used only within shared_ptr objects, at which point I would insist that requirement be enforced.
It's a little ridiculous to put typedefs for every unrelated template instantiation that you might use with a given object. Just because you might put MyClass in a shared_ptr is not a good reason to typedef it there. You going to put typedefs for std::vector, map, list, unordered_map, set, deque,....etc, etc, etc?
But if MyClass extends shared_from_this and has private/protected constructors so that it can ONLY be created and immediately assigned to a shared_ptr then...sure...it's part of the interface.
If you're trying to avoid having to type out long parameter lists to instantiate a shared_ptr for a templated type with lots of parameters then a better bet is an EXTERNAL utility object just like shown in the article you cited:
template < typename T >
struct instantiate_shared_ptr { typedef shared_ptr<T> type; };
template < typename after typename > struct my_complex_template {};
typedef my_complex_template<some parameters> mct_1;
typedef instantiate_shared_ptr<mct_1>::type mct_1_sp;
Yes, especially if the name MyClass_sp is referred to in client code.
This is probably good practice, it makes it simpler if you decide to change the underlying class the typedef refers to at a later date and (arguably) saves typos as well as making code easier to read even if it never changes. The particular choice of name here MyClass_sp leaves a little to be desired in my opinion though.
Also it's worth thinking carefully if making the typedef public or private is most appropriate, i.e. is it part of your public interface?
It's good, IMO.
I used it a lot.
If I want to use a container which element is the type of the my template, I typedef it.
Such as,
template <typename T>
class MyClass {
private:
typedef std::list<T> SomeContainerType;
typedef SomeContainerType::iterator IteratorType;
Then if I find any other structure more suitable, such as a vector, I can change the type without touching too much code.
A better solution for smart pointer typedefs is to do them after the class definition in the header:
namespace N
{
class A
{
};
typedef std::tr1::shared_ptr<A> APtr;
}
This keeps your smart pointer defintion near your class definition while preventing you (and any developers using your code) from having to write code like A::APtr a(new A) (which just looks odd).
EDIT: Since he is concerned with a template class:
namespace N
{
template<class T, class L>
class A
{
};
template<class T, class L>
struct A_Instantiator
{
typedef std::tr1::shared_ptr<A<T, L> > APtr;
};
}