Declaring a static pointer to an inner class object in a template - templates

I'm trying to create a simple template binary search tree for practice, and I currently have something like the following in a header file:
template <class T_Satellite, class T_Key>
class bst {
struct bst_node;
static const bst_node* nullnode;
}
My problem currently stems from trying to define nullnode in the cpp file. I've tried:
template <class T_Satellite, class T_Key>
const bst<T_Satellite, T_Key>::bst_node * bst::nullnode = bst_node(nullptr, nullptr);
and
template <class T_Satellite, class T_Key>
const bst<T_Satellite, T_Key>::bst_node * bst::nullnode(nullptr, nullptr);
But neither seem to work at all. I have a definition for bst_node in my cpp file as well. The compiler spits out that
'std::bst<T_Satellite,T_Key>::nullnode' : static data member cannot be initialized via derived class'
in the first example as well as
'std::bst<T_Satellite,T_Key>::bst_node' : dependent name is not a type.
Any ideas?

You need to use the typename keyword:
template <class T_Satellite, class T_Key>
const typename bst<T_Satellite, T_Key>::bst_node * bst::nullnode = bst_node(nullptr, nullptr);
The error message referencing "dependent name" is the clue. typename must be used for all dependent names that reference a type. A name is "dependent" if it involves an unbound template parameter.
Additionally, you'll almost certainly need to move this into your header file since the name will need to be instantiated with the actual used template parameters unless you're doing explicit instantiation.

Dependent names are those that depend on a template parameter. Dependent names are not treated as types to avoid ambiguity - the compiler doesn't have a way of knowing if the name refers to a member or a type. This is where you need to use the typename keyword.
Refer to the type bst_node as
template <class T_Satellite, class T_Key>
const typename bst<T_Satellite, T_Key>::bst_node

Related

Why do members of a template class need to be parameterized by the parameters of their template class

In page 668 of Stroustrup's book (4th edition - first printing) you`ll find the following example of a template class?
template<typename C>
class String{
public:
String();
...
private:
int sz;
C* ptr;
};
In page 679 the author writes:
Members of a template class are themselves templates parameterized by
the parameters of their template class. When such a member is defined
outside its class, it must explicitly be declared as template. For
example:
template<typename C>
String<C>::String()
:sz(0), ptr(ch)
{
ch[0] = {};
}
There is an obvious error in this example. The variable ch doesn't make any sense above. But that has nothing to do with my question. What I'd like to know is why the constructor above can't be defined without the parameter C, as shown below?
template<typename C>
String::String()
: sz(0), ptr(nullptr)
{
}
String is the name of a template, not a class. A template is not not even a type, so it doesn't have members. A template specialization is a class, however. You need to plug in C in order to specify which specialization it is you are referring to for the purposes of this definition.
Now it just so happens that the definition itself is a template, but that is because you are defining things for a family of specializations. Nevertheless the fact remains that you need to name those specializations explicitly.
Finally, the reason you only need to specify the specialization once is that the template name is treated in a special manner inside the scope of a class template specialization. Inside that scope the template name refers to the the injected class name, to the specialization itself. That's why
template<typename C>
String<C>::String<C>()
:sz(0), ptr(ch)
{
}
... can be written as...
template<typename C>
String<C>::String()
:sz(0), ptr(ch)
{
}
Since String<C> already established the specialization we are referring to, and we are inside its scope, we can use String with its special meaning as the injected class name.
C++ could have been designed with a special rule to make this trivial and common case work like you expect it to. The current rules are more consistent though, as they still work the in more complex cases.
In particular, consider the following :
template<typename C, int I> class String { };
template<typename C> class String<C,0> { String(); };
template<typename C> class String<C,1> { String(); };
This is a class template with two partial specializations.
Now the first ctor is defined as
template<typename C> String<C,0> :: String() { }
You see that the template argument list has one extra argument, ,0 which indicates the specific specialization. Partial specializations vary some, but not all template parameters of the base template. You have to specify which parameters can vary, and which have fixed values.

Using scope operator (::) in function header for return value [duplicate]

I've been working lately on a small project, and I couldn't figure out something..
I've been given a .h file that was containing a class, using a typename template. Inside that class there was a private class.
template <typename T>
class Something
{
public:
Something();
~Something();
Node* Function1(int index);
int Index(const T& id);
private:
class Node()
{
public:
T id;
//Imagine the rest for the Node
};
};
The problem occured when I wanted to define the functions of the class "Something"
Here's how I was doing it (in a .inl file)
template<typename T>
Node* Something::Function1(int index) //Is the return type well written?
{
// returns the node at the specified index
}
template<typename T>
int Something::Index(const T& id) //Is the parameter type well specified?
{
// returns the index of the node with the specified id
}
So the bugging part was in the definitions part... Do I have to tell the compiler that the return type (in this case Node*) uses the typename template (like this: typename Node*) ? And what about the parameter ? typename const Node& ?
So basically, when do I have to specify wether the function/parameter uses a template?
Thanks for your time.
For Function1, you need to tell the compiler what Node is -- in this case, it's a nested type inside Something<T>. Because it's dependent on T (it's a dependent name), you need to tell the compiler it's a type, so you must write it as typename Something<T>::Node. The issue is that there might be some T for which Something<T>::Node isn't actually a type (i.e. if you partially specialize Something<T>).
For Index, what you have is fine -- const T& is just a reference to a const T, and the compiler knows what T is.
The simple rule: You need to use the typename keyword every time you name a type using the Class::Type syntax, if the Class part depends on a template parameter. (The Class part might be a template parameter, or it might be a typedef in your class template, etc.)
Edit: There's also some confusion about nested class scoping rules. This is mostly independent of the typename issue, so here's a non-template example.
class Outer {
public:
class Inner {
};
Inner* func(Inner* obj);
};
Outer::Inner* func(Inner* obj)
{
}
The full name of Inner is Outer::Inner. But you can also use the shorter name Inner anywhere from the scope of class Outer, including all of the declaration of func. At the definition of func, the return type is NOT in the scope of Outer, so the full name is necessary. But after the (, the function parameters ARE in the scope of Outer, so the short name is okay.
Combining this with the template-ness of the original example, since the equivalent of Outer is Something<T>, you need the typename keyword to say Something<T>::Node.
template<typename T>
typename Something<T>::Node * Something::Function1(int index) //Is the return type well written?
{
// returns the node at the specified index
}
typename and class are equivalent in template type parameter list:
template <class T> class C;
is the same as
template <typename T> class C;
Where the typename is required is when referring to dependent names:
template <typename T> struct A {
typedef typename T::some_type container;
};

Protected member is unknown for derived class

I found an open source class library for Graphs. When I included it in my project it has many errors and I tried to fix them. But there is a compile error that I can not solve it.
Base class:
template <typename K, typename W, typename T>
class _base_graph
{
//...
protected:
std::map<K, T> nod;
std::list<edge> edg;
};
Derived class:
template <typename K, typename T = void*>
class graph : public _base_graph<K, void*, T>
{
//...
public:
void add_edge(const K& k1, const K& k2);
};
Method body:
template <typename K, typename T>
void graph<K, T>::add_edge(const K& k1, const K& k2)
{
if (nod.find(k1) == nod.end() || nod.find(k2) == nod.end()) // <-- error!!
throw std::string("add_edge: Node does not exist");
// ...
}
But my gcc compiler show me an error:
error: ‘nod’ was not declared in this scope
You can find and test mycode in this online compiler.
You need
this->nod.find(k2);
or
_base_graph<K, void*, T>::nod.find ....;
The base and the derived classes are templates, and in your code nod is a non-dependent name, and so is looked up at the point of graph's declaration. This is the first phase of the two-phase lookup. At this stage, it is impossible for the compiler (provided it follows the name lookup rules of the standard) to know what nod means, because it does not consider the base class until the second phase. So it is necessary to tell the compiler that nod should be looked up in the second phase. To do this, we explicitly tell it that nod is in a base class by using one of the forms above.
The reason for this behaviour is that at the point of the derived class' definition, it should not possible to know what _base_graph<K, void*, T>:: contains, to allow for specializations of the template that add and even hide names. So the trick above makes sure that the names are looked up at the point of the derived class' instantiation, when all the information is available.
In summary, there are two issues in play here:
nod is not a dependent name, so it would be looked up in the first phase.
The base class template, which declared nod, is not available until the second phase, so the name cannot be resolved.
By using this->nod or _base_graph<K, void*, T>::nod, we are explicitly dealing with a dependent name, forcing the lookup to take place in the second phase.
See points 7 to 10 here.
Thanks to #DavidRodriguez-dribeas for clarifying some of the finer points of the two phase look-up.
nod is a member of a dependent base (one that depends on template parameters). You either need to qualify the call with the name of the base, e.g. _base_graph<K, void*, T>::nod or with this->nod.
Alternatively you can also bring in names with using _base_graph<K, void*, T>::nod in either function or class scope.

Compile error with template return type for a function

I have a template class with this declaration in the .hpp:
template<class FriendClass> class SocialConnection{
typedef std::set<FriendClass> FriendSet;
FriendSet _socialFriends;
public:
virtual const FriendSet& getFriends();
And in the .cpp:
const SocialConnection::FriendSet& SocialConnection::getFriends() {
return _socialFriends;
}
The compiler gives me an error for the set declaration:
Expected a class or namespace for the line const SocialConnection::FriendSet& SocialConnection::getFriends()
I have been searching why for two hours and without any result. I can't use the name of my template class in the implementation? How I can do that? Anything of syntax that I have lost?
The class name in your getFriends definition is missing the template argument.
You can't really put your template code in a cpp file and expect it to compile. It is a template, so it is instantiated as a type wherever it is used. Therefore you will need to put it in a header.
template < typename F>
const typename SocialConnection< F>::FriendSet& SocialConnection< F>::getFriends() {
return _socialFriends;
}
The correct definition is rather long-winded:
template<typename FriendClass>
const typename SocialConnection<FriendClass>::FriendSet&
SocialConnection<FriendClass>::getFriends()
{
return _socialFriends;
}
And what #pwned said; it needs to be visible at the point of instantiation, so put it in the header. See this question for an explanation.
Note also typename before the return type - it's neccessary, because FriendSet is a dependent name. This question explains it in-depth.

Template class, static function compile error c++

I have the following function defined inside my linked list class. The declaration in the header file looks like this:
template <typename T>
class RingBuffer
{
...//stuff
static BLink * NewLink (const T&); // allocator
};
BLink is a "link" class within the RingBuffer class. The following implementation code:
template <typename T>
RingBuffer<T>::BLink * RingBuffer<T>::NewLink( const T& t ) // this is line 114
{
// create a new link in linked list
....
....
}
Is giving me this compile error:
./ringbuff.cpp:114: error: expected constructor, destructor, or type conversion before â*â token
I am stumped as to why it it needs an expected constructor, destructor, or type conversion before the return value.
The problem here is that you are referring to a nested dependent type name (i.e. BLink is nested inside RingBuffer which is dependent on a template parameter)
You need to help your compiler a little in this case by stating that RingBuffer<T>::BLink is an actual type name. You do this by using the typename keyword.
template <typename T>
typename RingBuffer<T>::BLink * RingBuffer<T>::NewLink(const T& t)
{
// ...
}
Explanation:
The compiler cannot know if RingBuffer<T>::BLink is a type name or a static member until the template parameter T is known. When the compiler parses your function template T is not known and the rule to solve the ambiguity is to default to "this is not a type name".
Another short example (blatantly copied from Scott Meyers' Effective C++):
template<typename C>
void print2nd(const C& container)
{
C::const_iterator * x;
…
}
This maybe illustrates the problem a little better as it's more compact. As already said it's not clear for the parser whether C::const_iterator is a type name or a static data member as it doesn't know what C is when it parses this part of the code (it may know at a later point in time when the template is actually instantiated). So to ease the compiler implementers' lives this ambiguity is resolved to "not a type name" and if the programmer wants to use a type name which is nested inside anything that is dependent on a template parameter he/she has to use the typename keyword in front of the name to let the compiler know that it should be treated as a type name.
Unfortunately there is an exception to that rule regarding nested dependent type names when using them inside a base class list or the base class identifier in a member initialization list.
template<typename T>
struct Base {
struct Nested {
Nested(int) {}
};
};
template<typename T>
struct Derived : public Base<T>::Nested { // typename not allowed here
Derived(int i)
: Base<T>::Nested(i) // nor here
{}
};
Btw: You should set your console client's charset to UTF-8, so you get ‘*’ instead of â*â.
compiler message is a little bit misleading.
In basically signifies syntax/parsing error.
Make sure the prototype is visible in compilation file, make sure you ring buffer is declared as template. and as other people have said, check the semi-column after class declaration.