I have a template class:
template<typename A, typename B>
class A {
};
In another .h file
template<typename A, typename B>
class A; //forward declaration
How could I declare m_A over here? I keep getting C++ forbids declaration of A with no type error:
class B {
A* m_A;
};
If you don't know the types that you want to instantiate A with when inside of B, then you will have to also make a template out of B
template<typename A1, typename B1>
class B
{
A<A1, B1>* m_A;
};
Either that, or you would have to instantiate A as a specific type, i.e.,
class B
{
A<Type_1, Type_2>* m_A;
};
Declare m_A with some specific types for A:
class B
{
A<int, char>* m_A;
}
If you B is such that you don't know a priori what types should be used in the m_A declaration, perhaps B needs to be template class and you'd use those type parameters in the declarion of m_A.
Templates are nice little peculiar beasts. The template definition must be available for the compiler at the place of instantiation, so the most common pattern is defining the template in the header so that each translation unit that uses the templated methods (and thus instantiates them) will have access to the definition.
Alternatively, you can provide the template definitions in a single translation unit, but you will have to ensure that you are instantiating the template for all the types for which you use it in the whole program.
// header
template <typename T> struct A
{
void foo( T );
}
// single translation unit
#include "header"
template <typename T> // template member definitino
void A<T>::foo( T x ) {
std::cout << "A(" << x << ")" << std::endl;
}
template struct A<int>; // explicit instantiation for int
template struct A<double>; // explicit instantiation for double
// main
#include "header"
int main() {
A<int> ai;
ai.foo( 5.5 ); // will print 5 (int rounded down)
A<double> ad;
ad.foo( 5.5 ); // will print 5.5
A<char> ac;
ac.foo( 'a' ); // linker error, A<char>::foo undefined
}
Because in general templates are meant to be used with any type through the program, defining the template methods in a single translation unit and using explicit instantiation is not a good idea. On the other hand, in the few cases where you need to control the set of types for which the template is instantiated, or under a few other circumstances (reducing large compile times [*]) you might want to follow this second approach. But again, in the general case, it is simpler to define the member functions in the header, and again it is simpler to defined them inside the class definition.
[*] Templates are compiled in all translation units in which they are used, which means that if you instantiate A<int>::foo in 5 different translation units, the compiler will compile it 5 times, and then the linker will discard 4 of the instantiations. In some cases where the template is complex, it might be an advantage to compile it once in one translation unit and just call it from the others. Note that with explicit instantiation, all member functions are compiled, while with implicit instantiation (at the place of use) only those members that are actually used will get compiled, so depending on the situation, explicit instantiation may be more costly than implicit instantiation (in classes with many members)
template<typename A>
void B<A>::function()
{
}
Btw, do not separate definitions and declarations while writing a template class.
EDIT:
changed < to < and > to >
Before that code looked like:
template
void B::function()
{
}
Related
I used to do what suggested here https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl to separate template header and implementations. We basically explicitly instantiate the desired template at the end of .cc file so that the compilation unit contains enough information for the linker to work with.
I recently learnt that we only need to explicitly instantiate a class constructor to be able to create an instance. For example,
// .h file
template<typename T>
class A {
public:
A(T& t) : t_(t) {};
void PublicMethod();
private:
void PrivateMethod();
T& t_;
};
// .cc file
template<typename T>
void A<T>::PublicMethod() { PrivateMethod; return;}
template<typename T>
void A<T>::PrivateMethod() {
// Do some work.
return;
}
// Here I only instantiate the constructor and public interface.
template A::A(int);
template void A<int>::PublicMethod();
// In main, I can do following.
int main() {
A<int> a(2);
a.PublicMethod();
}
The part I am not clear is:
if I instantiate the public method, does it automatically instantiate all relevant private methods as well automatically?
No, if you explicitly instantiate a member (including a constructor), then only the definition for that member will be explicitly instantiated.
The explicit instantiation may cause implicit instantiation of other members of the class, but that isn't enough to use these members in a different translation unit. If you do not intent to use the private members in a different translation unit though, then it would be sufficient to explicitly instantiate the public/protected member functions.
If you want to explicitly instantiate all class members, you should explicitly instantiate the class template specialization itself:
template class A<int>;
template A::A(int);
This is not correct. Your constructor expects a reference, so it should be int& instead of int. Furthermore A is the template, not a specialization of it. You must specify a specialization:
template A<int>::A(int);
Consider the following example:
template <typename T>
class A {
private:
typedef typename T::C C;
};
template <typename T>
class B : public A<B<T>> {
public:
typedef T C;
};
int main() {
B<int> b;
}
Compiling it with GCC gives the following error:
test.cc:5:23: error: no type named 'C' in 'B<int>'
typedef typename T::C C;
~~~~~~~~~~~~^
test.cc:9:18: note: in instantiation of template class 'A<B<int> >' requested here
class B : public A<B<T>> {
^
test.cc:15:10: note: in instantiation of template class 'B<int>' requested here
B<int> b;
^
Why does compiler give an error if B::C is defined and how to fix it?
At this point,
class B : public A<B<T>> {
… class B is incomplete. Class A can't look inside it.
The C type definition inside B is accessible from that point inside B, and on. It's also available inside function bodies in B because you can regard a function definition inside the class definition as a shorthand for placing it after the class. But an incomplete class contains nothing as viewed from outside: all that outside code can do is form pointers and references and use the class as template argument.
template< class C >
using Ungood = typename C::Number;
struct S
{
void foo() { Number x; (void) x; } // OK
Ungood<S> uhuh; //! Nyet.
using Number = double;
};
auto main() -> int {}
You can fix your code by changing the design. The most obvious is to pass the type as a separate template argument. But depending on what you're trying to achieve it may be that the inheritance you currently have, isn't really needed or even useful.
You can't because you're in a chicken-egg paradox. The definition of the base requires knowledge of the definition of the derived, which needs the definition of the base to complete. You simply have to come up with an alternative. One example would be to use an external metafunction to communicate the needed type to whoever needs it. Hopefully that's not in any part of the definition of the base's members or you're probably screwed.
Other alternative is to pass T as a second parameter.
You can't do that because of this:
A class is considered defined after the closing brace of its class-specifier has been seen [...]
And a few exceptions, none of which are valid in your case.
In other terms, you must consider your derived class as not fully defined when you try to use it in your base class to access the type C.
Anyway, you can exploit the fact that your derived class is a template class and do this:
template <typename T>
class A;
template <template<typename> class D, typename T>
class A<D<T>> {
private:
using C = T;
};
Aa you can see, I've not given a definition for the primary template class, thus only the specialization for template classes can be used.
Not sure this is the OP's real case, but it's the case in the example in the question.
Suppose I have:
template <typename T>
class A
{
//Do something with T
};
I know that the compiler will generate a class A<T> for each different T defined in the code.
What if I have:
class B
{
template <typename T>
void f() { /* Do something with T */ }
};
Would there be only one definition of class B but multiple overloads of f() for each different T it's called with?
Yes, with every instantiation of f<T> there will be a definition of f() generated by compiler.
Depending on the compiler, the f() could be optimized due to inlining or it can just acquire that much space in the code segment.
However, I have seldom came across this kind of design where you have a non-static template member function (without any argument!) inside a non-template class.
I am struggling to access static member function defined inside class template.
In the header file TemplateTest.h I defined the primary class Template as:
#include<iostream>
template<class T, class U>
struct TemplateTest
{
public:
void static invoke();
/*{
std::cout << "Should not be called" << std::endl;
}*/
};
Then Source File TemplateTester.cpp I put a specialization:
#include "TemplateTest.h"
template<>
struct TemplateTest<int, bool>
{
static void invoke()
{
std::cout << "invoke<int, bool>" << std::endl;
}
};
template struct TemplateTest<int, bool>; //instantiate to resolve linker issue
I explicitly instantiated the class with so linker resolves correctly.
In the driver driver.cpp :
include "TemplateTest.h"
int main()
{
TemplateTest<int, bool>::invoke();
return 0;
}
When I compile the TemplateTest.cpp with g++ it generates the object file correctly but when I try to link it to the driver class it gives my linker error "undefined reference to `TemplateTest::invoke()"
I went through other related postings like this one but I am not trying access a function template.
Any clue is much appreciated.
You are right that the object file you create from TemplateTester.cpp will contain a symbol for the specialization you provided. This is the case because any explicit specialization causes the template to be instantiated, and it is doubly the case because you even added an explicit instantiation (which is actually unnecessary).
However, at the time when driver.cpp is compiled, the compiler does not know about the specialization, because you only include TemplateTester.h, and the specialization isn't mentioned there. So the compiler instantiates the template, of course not using the specialized definition, so you get your problem.
The Standard says (Italics by me):
(§14.7.3/6) If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. [...]
So you need to make both, the declaration and the definition of the specialization known to the compiler when it works on driver.cpp. The best way of doing this is by adding the entire specialization to TemplateTester.h.
Note, again, that an explicit instantiation is not actually required.
There are several problems :
you do not need to explicitly instantiate fully specialized template
if you want to put your static method in the header, then use inline. Otherwise you will get multiple instances and linker problems
template specializations you put in the header, and define methods in the source files
if you do not want something to be called in a template, you don't need to define it. You'll get compiler errors, and that means catching errors earlier.
// TemplateTest.h
#include<iostream>
template<class T, class U>
struct TemplateTest;
template<>
struct TemplateTest<int, bool>
{
inline static void invoke()
{
std::cout << "invoke<int, bool>" << std::endl;
}
};
// main.cpp
include "TemplateTest.h"
int main()
{
TemplateTest<int, bool>::invoke();
}
Another way is to change the header, and add the source file.
// TemplateTest.h
#include<iostream>
template<class T, class U>
struct TemplateTest;
template<>
struct TemplateTest<int, bool>
{
static void invoke();
};
// TemplateTest.cpp
#include "TemplateTest.h"
void TemplateTest<int, bool>::invoke()
{
std::cout << "invoke<int, bool>" << std::endl;
}
I've just been reading about template explicit instantiation:
template struct MyStruct<long>;
It was described as "quite rare", so under what circumstances would it be useful?
One of the use cases is to hide definitions from the end-user.
tpl.h:
template<typename T>
void func(); // Declaration
tpl.cpp:
template<typename T>
void func()
{
// Definition
}
template void func<int>(); // explicit instantiation for int
template void func<double>(); // explicit instantiation for double
main.cpp
#include "tpl.h"
int main()
{
func<double>(); // OK
func<int>(); // OK
// func<char>(); - Linking ERROR
}
Explicit instantiation is designed to optimize template libraries usage providing some of (mostly used) template instances in compiled binary form instead of source code form. This will reduce compile and link time for end-user applications. E.g. std::basic_string<char> and std::basic_string<wchar_t> can be explicitly instantiated in STL distribution avoid work on its instantiation in each translation unit.
Explicit instantiation is also useful when you want to encapsulate template implementation and you want this template to be used only with well-known set of types. In this case you can place only declarations of template functions (free or members) in header file (.h/.hpp) and define them in translation unit (.cpp).
Example:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
// numeric_vector.cpp
//////////////////////////////////////////////////
// We know that it shall be used with doubles and ints only,
// so we explicitly instantiate it for doubles and ints
template class numeric_vector<int>;
template class numeric_vector<double>;
// Note that you could instantiate only specific
// members you need (functions and static data), not entire class:
template void numeric_vector<float>::sort();
template <typename T> void numeric_vector<T>::sort()
{
// Implementation
...
}
Also explicit instantiation can be useful when you need instantiated type from template but inside some syntax construction that doesn't trigger instantiation itself, e.g. some compiler-specific meta-feature like __declspec(uuid) in Visual Studio.
Note the difference with another technique that could be used for implementation encapsulation - explicit specialization. With explicit specialization you must provide specific definition for each type to be specialized. With explicit instantiation you have single template definition.
Consider the same example with explicit specialization:
Example:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
template <> class numeric_vector<int>
{
...
void sort();
};
template <> class numeric_vector<double>
{
...
void sort();
};
// Specializing separate members is also allowed
template <> void numeric_vector<float>::sort();
// numeric_vector.cpp
//////////////////////////////////////////////////
void numeric_vector<int>::sort()
{
// Implementation for int
...
}
void numeric_vector<double>::sort()
{
// Implementation for double
...
}
void numeric_vector<float>::sort()
{
// Implementation for float
...
}
Having an explicit specialization allows you to hide the implementation, which, as you know, is usually impossible with templates.
I've seen this technique only once in a library that handled geometry, and they'd provide their own vector class.
So you could use
lib::Vector<MyShape>
with some basic functionality that lib::Vector provided, and basic implementations, and if you used it with their classes (some, not all)
lib::Vector<lib::Polygon>
you would use the explicit specialization. You wouldn't have access to the implementation, but I'm betting some hardcore optimizations were going on behind the scenes there.
If you really don't like defining template functions in header files, you can define the functions in a separate source file and use explicit template instantiation to instantiate all the versions you use. Then you only need a forward declarations in your header file instead of the complete definition.