Where do I have to specify default template parameters of classes member functions (assuming that the declaration is (of course) in the "class body", and the function definition is outside the class body) for each case in C++2011 :
"normal" functions
static functions
friend functions
In the definition, in the declaration or both ?
Well,
From my experiences creating template classes and methods, you specify a template function as such:
template<typename T>
T MyFunc(T &aArg1, T &aArg2)
{
//...Definition Goes Here
}
The typename T is the template argument type for the template function and you need to pass that data type consistently to each argument labeled as "T". This means that aArg2 has to be whatever data type aArg1 is. Now, when you call this function, you call it like so:
MyFunc</*datatype*/int>(iArg1, iArg2); the two arguments have to be data type "int" or you'll get a warning or an error.
Now, this also applies to class methods (I think that is what you meant by "classes member functions") which are the functions supplied by the class (i.e. MyClass::MyFunc()) so when you declare a class method that is a template method, you do it in the same manner. Here is an example class:
class MyClass
{
MyClass();
~MyClass();
template<typename T>
static T MyStaticFunc(T aArg) { return aArg; }
template<typename T>
T MyFunc(T aArg) { return aArg; }
}
As you can see, not to difficult. Now, static functions are the same way you just have to be sure t define then in the same module that the class is built in, otherwise, you'll get an error.
Unfortunately, I never really use "friend" methods, so I don't know how to tackle that. I would suspect you would do it in the same way as the other two. I hoped that whole essay of an answer helped.
Trying these out in Clang suggests the following:
For non-static and static functions, specifying the default in either the definition or
the declaration is acceptable - but not both and certainly not if
they contradict one another;
For friend functions, specifying a
default inside the class definition results in an error.
Related
I'm wondering how template member functions work. In particular, when there is an instantiation of the template member function, is the whole class redefined? My confusion comes from the fact that (if I'm right) template classes are not classes in the proper sense. i.e., when instantiated, the compiler creates the definition for a completely new class. The same for template functions. However, classes with a template function seem to be actual classes, so I'm not sure how they could possibly work. Thus, I'm wondering, after instantiating a template member function, what happens with the class definition? Moreover, if I pass a class with a template member function to a template class, can I use the template member function? Could that cause a problem? I tried it once but got an error saying that several functions where defined more that once, although I'm not sure if that was the reason or if there could be an other reason for my error. Is there any further caveat when using static template member functions?
The class definition remains as it is; all the template function does is generate a family of member functions for that class. As an example:
class A {
public:
template<typename T> foo (T &t);
}
Is not conceptually different from you writing:
class A {
public:
foo (bool &t);
foo (int &t);
foo (double &t);
}
...just more convenient. And in the last example, you wouldn't expect a new class to be created for each function would you?
Perhaps the confusion comes from the notion that functions are somehow part of the memory layout of a class; that each function is itself contained in the class, and will be instantiated somewhere in memory whenever an object of the class is created. This notion is incorrect. Functions (templated, global, member, lambda, or otherwise) are never created on the fly or copied around in memory; they are a static and unchanging part of the executable image. The memory layout of the class is not changed by the presence of an extra set of functions, even if those happen to be generated by a template member.
The template class definition is instantiated when you instantiate a class. Each member function of it is instantiated when used. This actually allows you to have member functions that would not work if called when the class is instantiated with some types and not others. However, you must ensure that the signature of the function is either syntactically viable or fails with SFINAE. It will be looked up during the first phase of parsing. The body, if the function isn't itself a template, will be checked for name lookup...so dependent names have to be labeled as such via typename.
Is there a good rule when to use a class template instead of using member templates?
As I understand it, your are forced to use a class template if your class contains member variable templates but otherwise you are free of choice since this:
template<typename T>
class Foo
{
public:
void someMethod(T x);
};
behaves like this:
class Foo
{
public:
template<typename T>
void someMethod(T x);
};
Is my claim wrong? Or is there any rule of thumb when to use what?
The two are not at all the same. With the first:
Foo<int> f;
f.someMethod('a');
the called function is someMethod(int).
With the second:
Foo f;
f.someMethod('a');
the called function is someMethod(char).
You can choose to make your class a template, rather than having member function templates, for several reasons. Say you have a template parameter T.
Like you said, if you have a member variable of type T, your class needs to be a template.
If you have a function returning T and not accepting T, and you don't want to manually specify the type in each invocation, your class needs to be a template.
If you need a virtual function that depends on T, your class needs to be a template.
If you need a different class layout (i.e. member variables) per instantiation of T, your class needs to be a template.
If you need to make sure that your functions all operate on a single type rather than generate different versions of them arbitrarily, your class needs to be a template.
The best rule of thumb would be to use the simplest thing that makes sense. In general, member function templates tend to be more rare—and virtually non-existent for the use case you're talking about. Maybe that's no coincidence.
I am working on porting a project from C# to C++ and am having an issue when using templates, I need to have both a non-templated and a templated version of a class with one parented to another, ie:
class DataBuffer // Holds generic databuffer functions (getting size in bytes etc)
{
public:
int32 getVal() { return 10; }
};
template <typename T>
class DataBuffer<T> : public DataBuffer // Able to retrieve data as a type...
{
public:
int32 getSizeOfT() { return sizeof(T); }
};
I have methods that accept any type of DataBuffer as a parameter, so templating the entire class is not possible, is there any way of doing this without renaming the base class?
Any help would be greatly appreciated.
EDIT:
This code does not compile, and throws the following error at compile time:
error C2989: 'DataBuffer' : class template has already been declared as a non-class template
Unfortunately, there is no way of doing so. I think the relevant portion of the standard is:
A class template shall not have the same name as any other template,
class, function, object, enumeration, enumerator, namespace, or type
in the same scope (3.3), except as specified in (14.5.4). Except that
a function template can be overloaded either by (non-template)
functions with the same name or by other function templates with the
same name (14.8.3), a template name declared in namespace scope or in
class scope shall be unique in that scope.
However, the methods that should accept every type of DataBuffer could be made template too, so that inheriting from a common base would become unnecessary.
As the error says, a class template can't have the same name as a non-template.
You will have to rename either the base class or the template.
You'll need to give the class and the class template different names or put them into different namespaces: classes and class templates cannot have exactly the same name.
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
}
I have GetContainer() function as follows.
template<typename I,typename T,typename Container>
Container& ObjCollection<I,T,Container>::GetContainer()
{
return mContainer;
}
When I use this method as follows
template<typename I,typename T>
T& DynamicObjCollection<I,T>::Insert(T& t)
{
GetContainer().insert(&t);
return t;
}
I got errors.
error: there are no arguments to ‘GetContainer’ that depend on a template parameter,
so a declaration of ‘GetContainer’ must be available
error: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of
an undeclared name is deprecated)
It works fine with MSVC, but g++ is not so permissive. What's wrong with the code?
I noticed that the GetContainer function is a method of ObjCollection, while Insert is a member of DynamicObjectCollection. From this, I'm going to assume that DynamicObjectCollection inherits from ObjectCollection.
If this is indeed the case, the problem is that when you write a template class that inherits from a template base class, the way that name lookup works is slightly different from name lookup in normal classes. In particular, you cannot just reference base class members using their names; you need to indicate to the compiler where to look for the name. The reason this works in Visual Studio is that the Microsoft C++ compiler actually gets this behavior wrong and allows code that is technically illegal to compile just fine.
If you want to invoke the GetContainer function of the base class, you have two options. First, you can explicitly indicate that the call is to a member function:
this->GetContainer().insert(&t);
Now that the compiler knows that GetContainer is a member of DynamicObjectCollection, it knows that it might need to look up GetContainer in the base class, and so it will defer name lookup until the template is instantiated.
The other option available would be to add a using declaration into the class body:
template <typename I, typename T>
class DynamicObjectCollection: public ObjectCollection<I, T, /* ? */> {
public:
using ObjectCollection<I, T, /* ? */>::GetContainer;
/* ... */
};
This also indicates unambiguously to the compiler that GetContainer may be defined in the base class, and so it defers lookup until template instantiation.
If this isn't applicable to your situation, let me know and I can delete this post.
Hope this helps!