Does the following default argument for the template instantiates a template with type EmptyClass?
class EmptyClass{};
template <typename TYPE=EmptyClass>
class Sample
{
public:
static void test()
{
TYPE::Serialize();
}
};
No. Template are instantiated when used, and are instantiated on a per-function base.
Default parameter values are just the types to use when the parameter is not specified. But does not themselves imply usage.
When you call Sample<>::test() then Sample<Emptyclass>::test() is instantiated and the EmptyClass::serialize() call attempted, resulting in a compile-time error (Since Emptyclass is declared as not having such function)
Try to make up more function, containing different compile-time errors referring to different parameter, and you'll see how, until the function is not used, no error is produced.
No, in that code any instance of EmptyClass is created. Serialize is a static function. And EmptyClass's constructor is never called (in code showed)
Related
I've created a template class which triggers a runtime text output whenever an instantiation of it occurs:
template<typename T>
struct verbose {
verbose()
{
std::cout << "Instantation occured!" << std::endl;
}
};
template<typename T>
struct base
{
inline static verbose<T> v;
};
When I force to create instantiation, it shows an output:
template struct base<int>;
//output: Instantation occured!
(Check on Wandbox).
On the other hand, when I use it with a CRTP pattern, it seems that instantiation does not occur:
class test : public base<test>
{
};
(Check on Wandbox)
Is this behavior OK with the ISO standard? Can I somehow force to make instantiation, without requiring users of my template class (base) to write additional code? For me, the important thing is the side effect of the static variable constructor.
Your CRTP usage falls under implicit instantiation:
When code refers to a template in context that requires a completely defined type, or when the completeness of the type affects the code, and this particular type has not been explicitly instantiated, implicit instantiation occurs. For example, when an object of this type is constructed, but not when a pointer to this type is constructed.
This applies to the members of the class template: unless the member is used in the program, it is not instantiated, and does not require a definition.
cppreference
Following the second paragraph, since base<test>::v is never actually used, no instantiation of base<test>::v actually occurs.
Since a usage is required to generate its instantiation, there will need to be additional code to get your desired output. For example, you could add a constructor to base:
template<typename T>
struct base
{
inline static verbose<T> v;
base() { (void)&v; }
};
This alone is not enough to trigger your output based on the definition of test by itself. However, if your program tries to create an object from test, then the formation of the constructor will cause the template's constructor to be used, and thus base<test>::v will be instantiated.
I am very new on C++ templated code. could you please educate me on the following questions:
If I want to use function template (that only has non-type parameters) to define member function for a class, do I also need to define template for that class too. or in other word, does C++ allow user to define member function template (that has only non-type parameters) within untemplated class. for instance:
class foo{
template <int vecsize>
void bar(std::array<int, vecsize> vec);
};
thank you.
Yes, member function templates don't require the parent structure to be templatized (but it could be a template of course).
It seems you want a std::array instead of std::vector (as n.m. mentioned there is no size parameter for std::vector).
And you're missing a semicolon at the end of the class definition
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.
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.
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!