I have a library with a class templated on a size:
foo.hpp:
template <size_t N>
struct Foo {
void bar();
};
foo.cpp:
template <size_t N>
void Foo<N>::bar() {
...
};
I want the compiled version to be instatiated for a specific list of sizes which would be defined in the cpp file. In pseudocode, something like this
foo.cpp:
template <size_t N>
void Foo<N>::bar() {
...
};
for (const auto & size: {1,2,7,9})
template struct Foo<size>;
Right now, I am manually doing this (instatiating for each type), but this is error prone since I have several files that should be defined for the same size.
I am aware that I could move everything to the header file, and use some enable_if's to choose which sizes are valid. However, I want to hide the implementation details. Hence the current approach.
EDIT:
FWIW, I was hoping to avoid macros. I thought that something like this would work if you want a range of variables (e.g. 1,2,3,4...):
template<template<size_t> class E, size_t I = 1, std::enable_if_t<I >= 5> *unused = nullptr>
bool instatiator() {
return true;
}
template<template<size_t> class E, size_t I = 1, std::enable_if_t<I < 5> *unused = nullptr>
bool instatiator() {
E<I> e;
return instatiator<E, I + 1>();
}
bool unused = instatiator<Encoder>();
but I can't seem to get that working.
You could use an X macro approach for this:
valid_sizes.hpp
// Note: no include guards!!
PROCESS_SIZE(1)
PROCESS_SIZE(2)
PROCESS_SIZE(7)
PROCESS_SIZE(9)
#undef PROCESS_SIZE
foo.cpp
// ...
#define PROCESS_SIZE(n) template struct Foo<n>;
#include "valid_sizes.hpp"
bar.cpp
// ...
#define PROCESS_SIZE(n) some_other_use_of<n>;
#include "valid_sizes.hpp"
Alternatively, instead of a manual list, you could use Boost.Preprocessor:
process_sizes.hpp
#pragma once
#define PROCESS_SIZES(macro, data) BOOST_PP_SEQ_FOR_EACH(macro, data, (1)(2)(7)(9))
some header file
#define INSTANTIATE_CLASS(r, Name, size) template class Name<size>;
foo.cpp
#include "process_sizes.hpp"
// ...
PROCESS_SIZES(INSTANTIATE_CLASS, Foo)
bar.cpp
#include "process_sizes.hpp"
// ...
PROCESS_SIZES(INSTANTIATE_CLASS, Bar)
#define OTHER_SIZE_BASED_WORK(r, data, size) other_use_of<size>;
PROCESS_SIZES(OTHER_SIZE_BASED_WORK, whatever)
Note that explicit instantiation definitions must occur at namespace scope, so it's not possible put them inside a function like your attempted instantiator.
And also note that an implicit instantiation (such as would be caused by referring to the class in a context which requires it to be defined) is not "visible" outside the translation unit, so it cannot be used as a substitute for explicit instantiation.
In other words, having the same list of sizes do different things requires duplicating the list for each use, using macros, or using custom code generation outside of the C++ compilation pipeline. I consider macros the simplest and most maintainable of these.
In addition to #Angew answer:
xmacros can be in a different manner, allowing include guards and also avoiding having #include in the middle of the code:
valid_sizes.hpp
#pragma once
#define SIZES_TABLE(OP)\
OP(1) \
OP(2) \
OP(12)
foo.cpp
#include "valid_sizes.hpp"
// ...
#define INSTANTIATE(Size) template struct Foo<Size>;
SIZES_TABLE(INSTANTIATE)
#undef INSTANTIATE
You can recursively instantiate the Foo class with a helper class. Unfortunately you need to provide a call to each method of Foo in the constructor (the methods will not be called though), in order to provide the definitions to the linker:
// foo.cpp:
template <size_t S>
struct recursive_helper {
Foo<S> foo;
recursive_helper<S-1> r_helper;
recursive_helper() {
foo.bar();
foo.baz();
}
};
template <>
struct recursive_helper<0> {
Foo<0> foo;
recursive_helper() {
foo.bar();
foo.baz();
};
};
And then you instantiate the helper class:
template struct recursive_helper<6>;
Related
Sometimes I like my template class method definitions in a source file (or second header) to reduce build times. In all my source files I use a type alias for the class I'm defining the methods of to keep repetitions and typing time at a minimum.
Simple example:
// Foo.h
class Foo
{ void bar(); }
// Foo.cpp
using _ = Foo;
void _::bar()
{}
I have done this for template classes, which I want to keep the template parameter open of in method definitions, using MSVC.
// Foo.h
template<typename T>
class Foo
{ void bar(); }
// Foo.cpp
template<typename T>
using _ = Foo<T>;
template<typename T>
void _<T>::bar()
{}
However, while MSVC accepts this, GCC (12.2.0, MinGW) doesn't (invalid use of incomplete type). Am I maybe just doing it the wrong way or is it just not possible?
struct S
{
S(int);
S(std::string);
void foo(int);
void foo(std::string)
};
So my problem is that foo() should be invokable only with the type the ctor was. Solutions I can think of and problems with them:
Template the whole class. However this brings all the implementation details to the header, polluting it with many library #includes, making the API hard to read, making error messages long.
bool is_int runtime check. The assert() could be forgotten when implementing this API. The constraint is not evident from the API.
Separate classes. Violates DRY or forces all implementation to be extracted in .cpp-local functions - which is not so readable nor intuitive.
What other solutions are there? Or which of mine is the least silly?
Morally, your class is a template, but will only be instantiated with a type from a finite, known set of types. Your question is how to avoid some disadvantages of templates you identified: implementation details leaked, larger translation units, unintelligible API, and worse error messages.
The most straightforward way to implement this is to define and instantiate the templates out-of-line:
// S.h
#pragma once
#include <string>
#include <type_traits>
template<typename T>
struct S
{
static_assert(
std::is_same_v<T, int> ||
std::is_same_v<T, std::string>,
"S<T> only supports T=int or T=std::string"
);
S(T);
void foo(T);
};
extern template struct S<int>;
extern template struct S<std::string>
// S.cpp
#include "S.h"
#include <iostream>
template<typename T>
S<T>::S(T) { }
template<typename T>
void S<T>::foo(T t)
{
std::cout << "foo(" << t << ")\n";
}
template struct S<int>;
template struct S<std::string>;
// main.cpp
#include "S.h"
int main()
{
auto s = S{1};
s.foo(2); // prints "foo(2)\n"
}
Any translation units using S do not instantiate, and cannot instantiate, specializations of S. They rely on the instantiations provided. Implementation details are not exposed. Translation units are only as large as necessary to define the interface, not to implement it. The static assertion isn't required, but facilitates an early and obvious error.
As I got you have already implemented S. You can use the pimpl or S as a base class. Rename S to SImpl and make another templated S.
simpl.h
struct SImpl
{
SImpl(int);
SImpl(std::string);
void foo(int);
void foo(std::string)
};
s.h
#include "simpl.h"
template <typename T>
struct S: protected SImpl
{
S(T t) : SImpl(t) {}
void foo(T t) { SImpl::foo(t); }
};
In an effort to reduce compilation times in a large project that makes liberal use of templates, I've had good results using "extern template" (explicit template instantiation) to prevent common template functions from being defined in many different compilation units.
However, one annoying thing about it is that it doesn't work for member functions defined within the class definition.
For example, I have the following template class:
template <typename T>
struct Foo
{
static T doubleIt(T input)
{
return input * 2;
}
};
Now, I know that Foo is most commonly used for numeric types, so I add this to the header:
extern template struct Foo<int>;
extern template struct Foo<float>;
extern template struct Foo<double>;
And in a cpp file, add explicit instantiations:
template struct Foo<int>;
template struct Foo<float>;
template struct Foo<double>;
This does not work, as dumpbin.exe on the obj file tells me:
017 00000000 SECT4 notype () External | ?doubleIt#?$Foo#M##SAMM#Z (public: static float __cdecl Foo<float>::doubleIt(float))
If I change my class definition to define the function outside the class header like so it works correctly:
template <typename T>
struct Foo
{
static T doubleIt(T input);
};
template <typename T>
T Foo::doubleIt(T input)
{
return input * 2;
}
Which we can verify using dumpbin:
017 00000000 UNDEF notype () External | ?doubleIt#?$Foo#M##SAMM#Z (public: static float __cdecl Foo<float>::doubleIt(float))
The problem with that solution is that it is a lot of typing to move all the function definitions outside of the class definition, especially when you get more template parameters.
I've tried using declspec(__noinline) but it still doesn't extern the functions correctly (and preventing the inlining of the function where possible is undesirable).
One thing that works is to enumerate each function individually, like so, but that of course is even more cumbersome:
extern template int Foo<int>::doubleIt(int);
extern template float Foo<float>::doubleIt(float);
extern template double Foo<double>::doubleIt(double);
What I would like is a way to keep the function definition inside of the class definition, while still allowing the function to be inlined where possible, but when it is not inlined, only creating it in the compilation unit where it is explicitly instantiated (in other words, exactly the same behavior as moving the function outside of the class definition).
You can't have it both ways, in order to inline the method the compiler needs to use the source code, as the method is defined inline the compiler doesn't bother compiling it into an object file if it isn't used directly in that object (and even if it is if its inlined in all cases it wont be present in the object as a separate method).
The compiler will always have to build your function if its defined in the header, somehow forcing the compiler to store a copy of that function in the object file wont improve performance.
As has been pointed out, you cannot have both extern and inlining, but about the extra typing part, I did something like that and tried to minimize it using the preprocessor. I'm not sure if you'd find that useful, but just in case, I'll put an example with a template class that has a template function inside.
File Foo.h:
template<typename T1>
struct Foo
{
void bar(T1 input)
{
// ...
}
template<typename T2>
void baz(T1 input1, T2 input2);
};
#include <Foo.inl>
File Foo.cc:
template<typename T1>
template<typename T2>
void Foo<T1>::baz(T1 input1, T2 input2)
{
// ...
}
#define __FOO_IMPL
#include <Foo.inl>
#undef __FOO_IMPL
File Foo.inl:
#ifdef __FOO_IMPL
#define __FOO_EXTERN
#else
#define __FOO_EXTERN extern
#endif
#define __FOO_BAZ_INST(T1, T2) \
__FOO_EXTERN template void Foo<T1>::baz<T2>(T1, T2);
#define __FOO_INST(T1) \
__FOO_EXTERN template struct Foo<T1>; \
__FOO_BAZ_INST(T1, int) \
__FOO_BAZ_INST(T1, float) \
__FOO_BAZ_INST(T1, double) \
__FOO_INST(int)
__FOO_INST(float)
__FOO_INST(double)
#undef __FOO_INST
#undef __FOO_BAZ_INST
#undef __FOO_EXTERN
So it is still quite some writing, but at least you don't have to be careful to keep in sync to different sets of template declarations, and you don't have to explicitly go through every possible combination of types. In my case, I had a class template with two type parameters and with a couple of member function templates with an extra type parameter, and each of them could take one in 12 possible types. 36 lines is better than 123 = 1728, although I would have preferred the preprocessor to somehow iterate through the list of types for each parameter, but couldn't work out how.
As a side note, in my case I was compiling a DLL where I needed all the templates to be compiled, so actually the template instantiations/declarations looked more like __FOO_EXTERN template __FOO_API ....
I am trying to follow an example here:
http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
But I dont want to inline my function definitions with my class definition.
Will I have to put
template<typename Data>
concurrent_queue<Data>::
in front of all my function defs and constructors?
Yes, you will, and the definitions will still need to be in the header file. This is why everyone uses inline definitions- because they basically have to be inline anyway.
Yes, there is no way around that syntax (except with token-producing symbol-destroying evil evil #define macros).
Personally, I either inline them in the class template declaration/definition, or for the sake of better self-documentation put the definitions into some "inl"-file, like so:
foo.h
#ifndef FOO_H
#define FOO_H
namespace bar {
template <typename T>
class Foo {
public:
Foo () ;
virtual ~Foo();
};
}
#include "foo.inl.h"
#endif // FOO_H
foo.inl.h
#ifndef FOO_INL_H
#define FOO_INL_H
namespace bar {
template <typename T>
inline Foo<T>::Foo () {
}
template <typename T>
inline Foo<T>::~Foo () {
}
}
#endif // FOO_INL_H
Note that I explicitly declare them inline then. This improves consistency of the style, and if you happen to specialize the template, you have to do it anyways:
template <>
inline Foo<int>::Foo() {
}
Without the inline, you suffer the same pain like when forgetting it on ordinary functions defined in header files (read: multiple definition errors).
The functions do not need to be inline, but it's better if they are inside the header file:
/* in .h file */
template<class T>
class A
{
public:
void f();
}
/* this also in .h file */
template<class T>
void A<T>::f()
{
}
This is often necessary to split the class and the functions to separate parts, but both of them needs to be in the header file for templates to work.
When I specialize a (static) member function/constant in a template class, I'm confused as to where the declaration is meant to go.
Here's an example of what I what to do - yoinked directly from IBM's reference on template specialization:
===IBM Member Specialization Example===
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
int main() {
X<char*> a, b;
X<float> c;
c.f(10); // X<float>::v now set to 20
}
The question is, how do I divide this into header/cpp files? The generic implementation is obviously in the header, but what about the specialization?
It can't go in the header file, because it's concrete, leading to multiple definition. But if it goes into the .cpp file, is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?
So far I've got the specialization in the .cpp only, with no declaration in the header. I'm not having trouble compiling or even running my code (on gcc, don't remember the version at the moment), and it behaves as expected - recognizing the specialization. But A) I'm not sure this is correct, and I'd like to know what is, and B) my Doxygen documentation comes out wonky and very misleading (more on that in a moment a later question).
What seems most natural to me would be something like this, declaring the specialization in the header and defining it in the .cpp:
===XClass.hpp===
#ifndef XCLASS_HPP
#define XCLASS_HPP
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
/* declaration of specialized functions */
template<> char* X<char*>::v;
template<> void X<float>::f(float arg);
#endif
===XClass.cpp===
#include <XClass.hpp>
/* concrete implementation of specialized functions */
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
...but I have no idea if this is correct. Any ideas?
Usually you'd just define the specializations inline in the header as dirkgently said.
You can define specializations in seperate translation units though if you are worried about compilation times or code bloat:
// x.h:
template<class T> struct X {
void f() {}
}
// declare specialization X<int>::f() to exist somewhere:
template<> void X<int>::f();
// translation unit with definition for X<int>::f():
#include "x.h"
template<> void X<int>::f() {
// ...
}
So yes, your approach looks fine. Note that you can only do this with full specializations, thus it is often impractical to do this.
For details, see e.g. Comeaus template FAQ.
Put them all in a hpp file. Make the specializations and anything you define outside the class inline -- that'll take care of multiple definitions.
To answer one of your questions: is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?
If the compiler sees a definition which matches its requirements, then it will use it. Else it will generate normal function calls.
In your first code snippet, you supply a generic definition for X<T>::f(T arg), so the compiler will instantiate that for any T apart from float.
If you were to omit the generic definition, then the compiler would generate calls to, say, X<double>::f(double) and the linker would go searching for the definition which might end with a linker error.
To summarise: You can have everything in headers, because as templates you won't get multiple definitions. If you only have declarations, you will need definitions elsewhere for the linker to find later.
Using template void X<float>::f(float arg) { v = arg * 2; } instead.