What is the best pratice in regards to defining a template in C++?
template <class T>
class A
{
private:
// stuff
public:
T DoMagic()
{
//method body
}
}
Or:
template <class T>
class A
{
private:
// stuff
public:
T DoMagic();
}
template <class T>
A::T DoMagic()
{
// magic
}
Another way?
I seem to stumble over some controversy regarding this subject.
So; What path to choose?
This is completely a matter of style. That said however:
choose a way and stick to it -- either all inline, or all out, or mixed based on some rule
personally I use a 3 line rule. If the method body in the template is longer than 3 lines I move it outside.
There's no real reason not to include all definitions inline (they are inline from the compilers POV anyway), however, many people argue that keeping them separate is more clean, and allows the class definition to be more readable.
Use an increasing level of separation as the templates you write grow larger and more complex.
Performance will be the same no matter how you separate the definitions from the declarations, so your main concern here should be readability and maintainability.
When writing a simple template used only in one place, declare and define it inline with the declarations right in the CPP file where you're going to use it. There's no reason to force a global recompile if only one block of code needs this template.
file.cpp
template<class Gizmo> bool DoSomethingFancy()
{
// ...
}
For small template utilities used across translation units, define and declare them together in an H file:
utility.h
template<class Gizmo> bool DoSomethingUseful()
{
// ...
}
As your templates become more complex it will become more important to be able to view the declaration separately from the definition. At first, keep everything separate but in the same file:
utility.h
template<class Type> class Useful
{
bool FunctionA();
bool FunctionB();
};
template<class Type> bool Useful<Type>::FunctionA()
{
// ...
}
template<class Type> bool Useful<Type>::FunctionB()
{
// ...
}
But eventually even this will become unwieldly. When it does, separate it in to a header file for the declarations, and an INC file for the definitions. At the end of the header file, #include the INC file:
utility.h :
template<class Type> class MoreUseful
{
bool FunctionA();
bool FunctionB();
};
#include "utility.inc"
utility.inc :
template<class Type> bool MoreUseful<Type>::FunctionA()
{
// ...
}
template<class Type> bool MoreUseful<Type>::FunctionB()
{
// ...
}
This is a religious (style) issue. I prefer to define my functions outside of the template declaration for classes that have more than one method or the few methods are simple.
In either case, my understanding is that the template declaration and the method definitions must be in the same translation unit. This is because the template is more like a stencil, the compiler plugs a given type into the stencil and generates code for the given type.
Whatever you decide, just be consistent.
I usually define all the methods outside but each time I wish C++ had some sort of "template blocks":
template <class T>
struct A
{
T foo();
T bar(T * t);
T baz(T const & t);
};
template <class T> // Made-up syntax
{
T A::foo()
{
//...
}
T A::bar(T * t)
{
//...
}
T A::baz(T const & t)
{
//...
}
}
If the functions are non-trivial (i.e. more than one or two lines), consider defining them separately. This makes the interface of the class much easier to navigate, read and understand for the users of your class, who most likely shouldn't have to look at the actual implementation of each method.
For a one-off instance like your example, it makes little difference.
What happens when there are lots of templates with lots of variations? It then helps to put similar types of apples together, and similar types of oranges together away from them. Of course, this must all be done as intuitively as practical. That is greatly affected by the culture of programmers working with the code.
Related
I am having a problem with the changes that were made to the way C++ templates are compiled, between the C++17 and 19 standards. Code that used to compile in VS2017 throws a compiler error since I upgraded to VS2019 or VS2022.
Situations have to do with the fact that the compiler now runs a basic syntax check on the template definition when it sees this definition ("first pass") and not only when the template is actually used.
Code example 1:
class Finder
{
template<typename T>
T convert_to(HANDLE h)
{
return Converters::Converter<T>::Convert(get_data(h));
}
};
Here, the template class Converter<> resides in namespace Converters, and get_data is a member function of Finder which returns something that can be passed into the Convert function.
Since we're dealing with templates, this code sits in a header file "Finder.h". The header file doesn't #include "Converters.h". Finder.h is shared across several projects, some of which don't even know the Converters.h file namespace.
As long as no code calls the MyClass::convert_to<> function, this compiles in VS2017, but not so in VS2019 and VS2022:
error C3861: 'Converters': identifier not found
The obvious solution is, of course, to #include "Converters.h" either in this header file, or in the precompiled headers file. However, as was said, Converters.h is not known in all places which use MyClass. Another solution would be to use archaic #define CONVERTERS_H in the Converters.h header and enclose the function definition in #ifdef CONVERTERS_H, but this looks really ugly.
My question is: Is there a way to prevent the compiler from doing this "first pass"? Or to re-write this code so that it compiles? I don't mind if it's MS specific; no other compiler will ever see the code.
Code example 2:
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) { static_assert(false, "Don't do this"); }
// lots more member functions, most of them 'static'
};
template<> void MyClass::DoSomething(CWnd* ptr) { /*some useful code*/ }
/// and some more specializations of DoSomething
The intention is that the static_assert should emit an error message whenever DoSomething is called with an argument for which no explicit specialization of this template function is defined. This worked in VS2017, but in VS2022, the "first pass" of the compiler triggers the static_assert.
Again, I wonder how I could achieve this effect, other than by replacing the static_assert by a run-time assertion.
Or am I thinking into a completely wrong direction?
Thanks
Hans
The first case requires a forward declaration of some kind, that's unavoidable.
The second case, though, can be handled with just a minor change.
#include <type_traits>
class CWnd {};
class MyClass2
{
public:
template<class T, class Y=T>
static void DoSomething(T* ptr) { static_assert(!std::is_same_v<Y,T>, "Don't do this"); }
};
template<> void MyClass2::DoSomething(CWnd* ptr) { /*some useful code*/ }
void foo()
{
int a;
CWnd b;
MyClass2::DoSomething(&a); // ERROR
MyClass2::DoSomething(&b); // OK
}
(partial answer)
To fix MyClass2, the usual trick is to make false depend on T, so that the first pass does not trigger the assert.
// dependent false
template <typename>
constexpr bool dep_false() { return false; }
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) {
static_assert(dep_false<T>(), "Don't do this");
}
// lots more member functions, most of them 'static'
};
// specialization example
template<>
void MyClass2::DoSomething<int>(int* ptr) {
std::cout << "int* is OK\n";
}
I have a fixed set of four types A, B, C and D, and a large amount of class and function templates that work with these types.
To reduce compile times, I would like to put the definition of these templates into .cpp files and explicitly instantiate the templates for this fixed set of types.
However, the explicit instantiation introduces a lot of boilerplate code, which I would like to reduce. Is there an elegant way of explicitly instantiating function and class templates for a fixed set of types?
Here's some code to illustrate the problem:
#include <iostream>
class A { public: int foo() const { return 0; } };
class B { public: int foo() const { return 1; } };
class C { public: int foo() const { return 2; } };
class D { public: int foo() const { return 3; } };
template<typename T>
class SomeClass {
/* could have a member variable of type A-D */
T m_t;
/* or several functions which take such a type */
void printFoo(const T& t){
std::cout << t.foo() << "\n";
}
};
/* normal explicit instantiation */
//template class SomeClass<A>;
//template class SomeClass<B>;
//template class SomeClass<C>;
//template class SomeClass<D>;
/* or something with macros, but hopefully better than this: */
#define INSTANTIATE_FOR_ALL_TYPES \
INSTANTIATE_WITH(A) \
INSTANTIATE_WITH(B) \
INSTANTIATE_WITH(C) \
INSTANTIATE_WITH(D)
/* if this here could be one line instead of three, then you found the answer */
#define INSTANTIATE_WITH(TYPE) template class SomeClass<TYPE>;
INSTANTIATE_FOR_ALL_TYPES
#undef INSTANTIATE_WITH
int main(){
return 0;
}
I wouldn't use explicit instantiation if it weren't certain from the design of the program that the types won't change. Also, I'm aware that for compiling the code once, the compile time is not affected by explicit instantiation. However, when writing tests which include many templates, and recompilation is done often, the effect is very noticeable.
If there's another option to achieve shorter compilation times, I'm open to it.
For now, until someone finds a better solution, the following works well enough:
#define INSTANTIATE_FOR_ALL_TYPES(TYPE) template class SomeClass<TYPE>;
#include "instantiator.hpp"
with the contents of instantiator.hpp being
/* lack of a header guard is intentional */
INSTANTIATE_FOR_ALL_TYPES(A)
INSTANTIATE_FOR_ALL_TYPES(B)
INSTANTIATE_FOR_ALL_TYPES(C)
INSTANTIATE_FOR_ALL_TYPES(D)
#undef INSTANTIATE_FOR_ALL_TYPES
Typos and similar mistakes are caught by the preprocessor. This works well for instantiating several functions/classes with minimal code duplication:
#define INSTANTIATE_FOR_ALL_TYPES(TYPE) \
template class SomeClass<TYPE>; \
template class AnotherClass<TYPE>; \
template void foo( const TYPE& );
#include "instantiator.hpp"
If someone can spot problems with this approach, I'd welcome the feedback. But I'd prefer "this could cause problem x under circumstances y" over "macros are evil" and "this is not how you should use #include".
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
I looked around for a good solution to avoid code duplication on each spezialization of a template class.
Here is an example code:
template<class T>
class C
{
int foo();
}
Now the definition for defaults:
template<class T>
C<T>::foo() { return 0; }
Now the spezailization for special templates
template<> C<int>::foo() { ... do a lot of stuff and return n .... }
template<> C<double>::foo() { ... do a lot of stuff and return n .... }
template<> C<int>::foo() { ... do a lot of stuff and return n .... }
Right now I have to duplicate the code for the spezailization. But in general it's the same code.
My questions is:
What is the best solution to avoid code duplication here and how can I hide the implementation ? Maybe by using a noname-namespace or an impl-namespace ?
Kind regards,
Peter
You can do as with any other class: extract the boilerplate code to another (private) function in the template class and call this one in your specializations.
template<class T>
class C
{
int foo();
void bar() { /* does lot of stuff ... */ }
};
template<> int C<int>::foo() { bar(); return n .... }
template<> int C<double>::foo() { bar(); return n .... }
and how can I hide the implementation ? Maybe by using a noname-namespace or an impl-namespace ?
It's not really possible to hide the implementation of template code, by means of having a compilation unit specific unnamed namespace.
If your intend mainly is to get a cleaner readable template header file, you can factor out the implementation to another included file. These are often named .tcc or .icc, there are samples for this technique in most of the c++ implementation standard header files.
One way to avoid duplicating code is to use a base class to handle generic implementation:
template <class T>
class base_C
{
void generic_foo(){...}
};
template <>
class C <SpecialType> : base_C<SpecialType>
{
void foo()
{
SpecialType::custom_foo();
base_C<SpecialType>::generic_foo();
}
};
The idea begind this is to split foo into more generic parts and put them into base_C. With this each specialization of C::foo will have a minimal amount of custom code.
I'm trying to build a wrapper around a managed class so I can call it from native code.
Here is the managed function :
void MyManagedFunction(MyStruct iStruct)
{
// Code according to what are the types of the 2 MyStruct members
}
struct MyStruct
{
public MyStruct(Object iValue1, Object iValue2) : this()
{
Value1 = iValue1; // Often contains DateTime::Now
Value2 = iValue2;
}
public Object Value1;
public Object Value2;
}
In my case, Value1 will almost always be System::DateTime::Now and the Value2 will almost always be a common data type (int, double, float, string, bool). I thought of making two templated function in the wrapper.
In the wrapper's .h I have the following :
#ifdef MYWRAPPER_EXPORTS
# define MYWRAPPER __declspec(dllexport)
#else
# define MYWRAPPER __declspec(dllimport)
#endif
class MYWRAPPER MyWrapper
{
public:
MyWrapper();
~MyWrapper();
template <class T> void MyNativeFunction(T iParam1)
{
MyStruct^ wStruct = gcnew MyStruct(System::DateTime::Now, iParam1);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
template <class T, class W> void MyNativeFunction(T iParam1, W iParam2)
{
MyStruct^ wStruct = gcnew MyStruct(iParam1, iParam2);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
};
This wrapper compiled without problem. The problem obviously occurred when I included the .h in the purely native code. Since I can't hide the content of the templated function, I have managed stuff visible on the native side which prevent the native code from compiling.
I was wondering if there was a workaround in order to achieve this. I don't mind if I'm limited into using only primitive types as parameters for the function. The best thing is if I was able to simply hide the content of the templated function in the native code so it only knows about the signature
Here's what I've tried/considered so far :
Converting the parameters to void* and call a function in which would call the managed one. By doing so, I can't cast the void* back to an object since I lose its type and using typeid to get the 'T' or 'W' type doesn't help since it vary from a compiler to another.
Overloading the function for every types I want to use. This is what I'll most likely use if I doesn't find a better solution. The problem is it means alot of overloading (especially for the 2 parameters function considering the number of combination)
If you know all the types your template will take, you can force instantiate it with those variables and thus put the code for the template functions in the source file instead of a header.
You can look at the example provided in Storing C++ template function definitions in a .CPP file
As he says you can do as below (copy-paste alert):
.h file
class foo
{
public:
template <typename T>
void do(const T& t);
};
.cpp file
template <typename T>
void foo::do(const T& t)
{
// Do something with t
}
template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
How do I inherit from a virtual template class, in this code:
// test.h
class Base {
public:
virtual std::string Foo() = 0;
virtual std::string Bar() = 0;
};
template <typename T>
class Derived : public Base {
public:
Derived(const T& data) : data_(data) { }
virtual std::string Foo();
virtual std::string Bar();
T data() {
return data_;
}
private:
T data_;
};
typedef Derived<std::string> DStr;
typedef Derived<int> DInt;
// test.cpp
template<typename T>
std::string Derived<T>::Foo() { ... }
template<typename T>
std::string Derived<T>::Bar() { ... }
When I try to use the DStr or DInt, the linker complain that there are unresolved externals, which are Derived<std::string>::Foo() and Derived<std::string>::Bar(), and the same for Derived<int>.
Did I miss something in my code?
EDIT:
Thanks all. It's pretty clear now.
You need to define template<typename T> std::string Derived<T>::Foo() { ... } and template<typename T>
std::string Derived<T>::Bar() { ... } in the header file. When the compiler is compiling test.cpp it doesn't know all the possible values of T that you might use in other parts of the program.
I think there are some compilers that have connections between the compiling and linking steps that notice references to missing template instantiations and go instantiate them from the .cpp file where they are declared. But I don't know which they are, and the functionality is exceedingly rare to find.
If you define them in the header file most compilers will emit them as a 'weak' symbol into every compilation unit in which they're referenced. And the linker will toss out all except for one definition of the weak symbol. This causes extra compilation time.
Alternately, there are syntaxes for explicitly instantiating templates and forcing the compiler to emit definitions right there. But that requires you to be aware of all the values T could possibly have and you will inevitably miss some.
You have to ensure that the member functions are instantiate for all the required types somewhere.
Usually this is accomplished by defining template functions inline in the header file where they are declared so that any use of the functions will cause them to be instantiated.
As an alternative, you can use explicit instantiations in the source file where you define them but this does require you to know in advance all the types that your template will ever be instantiated for.
This doesn't really have much to do with derivation. It's just a general rule with templates: with most compilers (anything but Comeau) you have to put the full implementation of a template where it's visible in every translation unit that will instantiate that template -- normally in the header.
Even with Comeau, you have to use the export keyword to make things work right. Since They're the only ones that implement export, chances are pretty good that you don't care much though.