How would you cleanly follow the Stepdown rule in C/C++? - c++

The Stepdown rule encourages to read the code like a top-down narrative. It suggests every class/function to be followed by those at the next level of abstraction so we can read the code descending in the level of abstraction.
In C/C++ you need to declare classes/functions before you use them. So how would cleanly apply the Stepdown rule here? What are some pros and cons of the following approach? Any better one?
void makeBreakfast();
void addEggs();
void cook();
void serve();
int main()
{
makeBreakfast();
}
void makeBreakfast()
{
addEggs();
cook();
serve();
}
void addEggs()
{
// Add eggs.
}
void cook()
{
// Cook.
}
void serve()
{
// Serve.
}

My approach is like yours but with either making a class so the declaration can come after use, or put declarations in a header file.

Related

C++ Compile time check if a function called before another one

Lets say I have a class with two member functions.
class Dummy {
public:
void procedure_1();
void procedure_2();
};
At compile time, I want to be sure that, procedure_1 is called before procedure_2. What is the correct way do implement this?
Maybe you could do it with a proxy-class. The idea is, that procedure_2 can't be accessed directly from outside (for example by making it private). procedure_1 would return some kind of proxy that allows the access to procedure_2.
Some code below, allthough I don't consider it clean or safe. And if you want, you can still break the system.
IMO such requirements should be handled without explicit validation, because it's quite cumbersome and impossible to make it absolutely safe.
Instead, the dependency should be well documented, which also seems idiomatic in C++. You get a warning that bad things might happen if a function is used incorrectly, but nothing prevents you from shooting your own leg.
class Dummy {
private:
void procedure_2() { }
class DummyProxy
{
private:
Dummy *parent; // Maybe use something safer here
public:
DummyProxy(Dummy *parent): parent(parent) {}
void procedure_2() { this->parent->procedure_2(); }
};
public:
[[nodiscard]] DummyProxy procedure_1() {
return DummyProxy{this};
}
};
int main()
{
Dummy d;
// d.procedure_2(); error: private within this context
auto proxy = d.procedure_1(); // You need to get the proxy first
proxy.procedure_2(); // Then
// But you can still break the system:
Dummy d2;
decltype(d2.procedure_1()) x(&d2); // only decltype, function is not actually called
d2.procedure_2(); // ooops, procedure_1 wasn't called for d2
}
Instead of "checking" it, just do not allow it. Do not expose an interface that allows to call it in any other way. Expose an interface that allows to only call it in specified order. For example:
// library.c
class Dummy {
private:
void procedure_1();
void procedure_2();
public:
void call_Dummy_prodedure_1_then_something_then_produre_2(std::function<void()> f){
procedure_1();
f();
procedure_2();
}
};
You could also make procedure_2 be called from destructor and procedure_1 from a constructor.
#include <memory>
struct Dummy {
private:
void procedure_1();
void procedure_2();
public:
struct Procedures {
Dummy& d;
Procedures(Dummy& d) : d(d) { d.procedure_1(); }
~Procedures() { d.procedure_2(); }
};
// just a simple example with unique_ptr
std::unique_ptr<Dummy::Procedures> call_Dummy_prodedure_1_then_produre_2(){
return std::make_unique<Dummy::Procedures>(*this);
}
};
int main() {
Dummy d;
auto call = d.call_Dummy_prodedure_1_then_produre_2();
call.reset(); // yay!
}
The above are methods that will make sure that inside one translation unit the calls will be ordered. To check between multiple source files, generate the final executable, then write a tool that will go through the generated assembly and if there are two or more calls to that call_Dummy_prodedure_1_then_produre_2 function that tool will error. For that, additional work is needed to make sure that call_Dummy_prodedure_1_then_produre_2 can't be optimized by the compiler.
But you could create a header that could only be included by one translation unit:
// dummy.h
int some_global_variable_with_initialization = 0;
struct Dummy {
....
};
and expose the interface from above into Dummy or add only the wrapper declaration in that library. That way, if multiple souce files include dummy.h, linker will error with multiple definitions error.
As for checking, you can make prodedure_1 and procedure_2 some macros that will expand to something that can't be optimized by the compiler with some mark, like assembly comment. Then you may go through generated executable with a custom tool that will check that the call to prodedure_1 comes before procedure_2.

C++ Namespace around header declaration and source definition

I am making a static library, everything defined in it is all in one namespace. But I am unsure whether I should define the methods as if you would a class, or also wrap them in the namespace. What I'm asking is:
Is this valid:
MyThings.h
namespace MyThings {
void DoStuff();
void DoOtherStuff();
}
MyThings.cpp
namespace MyThings {
void DoStuff() {
// Do this.
}
void DoOtherStuff() {
// Do that.
}
}
Or, should I define it like I would class methods?:
MyThings.cpp
void MyThings::DoStuff() {
// Do this.
}
void MyThings::DoOtherStuff() {
// Do that.
}
I would prefer not to use using namespace MyThings;, and I would prefer to use my first example if it is valid, I feel it makes the code more readable without having to use MyThings:: before every method identifier.
Both are valid, so you can pick your style according to taste.
There is an advertised advantage of defining the function using:
void MyThings::DoStuff() {
// Do this.
}
which is that in order to do it, the function must have already been declared. Thus, errors like:
void MyThings::DoStuf() {
// Do this.
}
or
void MyThings::DoStuff(int i) {
// Do this.
}
are caught when you compile MyThings.cpp. If you define
namespace MyThings {
void DoStuff(int i) {
// Do this.
}
}
then you generally won't get an error until someone in another source file tries to call the function, and the linker complains. Obviously if your testing is non-rubbish you'll catch the error one way or another, but sooner is often better and you might get a better error message out of the compiler than the linker.

Can I use templates/macros/both to wrap each function of a C++ class?

Suppose I had this.
class A {
public:
int f1();
int f2();
}
Is there any way to use templates/macros/both to generate a class that behaves like the following?
class GeneratedClass {
public:
GeneratedClass(InjectedFunction injected_function) { /* store it */ }
int f1() {
injected_function();
/* forward call to "inner class" and return its value */
}
int f2() {
injected_function()
/* forward call to "inner class" and return its value */
}
}
Basically I want to be able to generate a class that supports all the functions of a given class, but doing something before it blindly forwards the call.
This class will be created with something like.
SomeClassTemplate<A> infected_a(injected_function);
No, templates cannot generate that code for you automatically. You must write it by hand.
It sounds like you want aspect-oriented C++. This link discusses implementing aspect-oriented C++ with pure C++ and also with a language extension.
See also here for an implementation.
Aspect-oriented programming is about separation of concerns in a project. Insertion points are specified where code is inserted. Sounds like exactly what you want.

C++ handling specific impl - #ifdef vs private inheritance vs tag dispatch

I have some classes implementing some computations which I have
to optimize for different SIMD implementations e.g. Altivec and
SSE. I don't want to polute the code with #ifdef ... #endif blocks
for each method I have to optimize so I tried a couple of other
approaches, but unfotunately I'm not very satisfied of how it turned
out for reasons I'll try to clarify. So I'm looking for some advice
on how I could improve what I have already done.
1.Different implementation files with crude includes
I have the same header file describing the class interface with different
"pseudo" implementation files for plain C++, Altivec and SSE only for the
relevant methods:
// Algo.h
#ifndef ALGO_H_INCLUDED_
#define ALGO_H_INCLUDED_
class Algo
{
public:
Algo();
~Algo();
void process();
protected:
void computeSome();
void computeMore();
};
#endif
// Algo.cpp
#include "Algo.h"
Algo::Algo() { }
Algo::~Algo() { }
void Algo::process()
{
computeSome();
computeMore();
}
#if defined(ALTIVEC)
#include "Algo_Altivec.cpp"
#elif defined(SSE)
#include "Algo_SSE.cpp"
#else
#include "Algo_Scalar.cpp"
#endif
// Algo_Altivec.cpp
void Algo::computeSome()
{
}
void Algo::computeMore()
{
}
... same for the other implementation files
Pros:
the split is quite straightforward and easy to do
there is no "overhead"(don't know how to say it better) to objects of my class
by which I mean no extra inheritance, no addition of member variables etc.
much cleaner than #ifdef-ing all over the place
Cons:
I have three additional files for maintenance; I could put the Scalar
implementation in the Algo.cpp file though and end up with just two but the
inclusion part will look and fell a bit dirtier
they are not compilable units per-se and have to be excluded from the
project structure
if I do not have the specific optimized implementation yet for let's say
SSE I would have to duplicate some code from the plain(Scalar) C++ implementation file
I cannot fallback to the plain C++ implementation if nedded; ? is it even possible
to do that in the described scenario ?
I do not feel any structural cohesion in the approach
2.Different implementation files with private inheritance
// Algo.h
class Algo : private AlgoImpl
{
... as before
}
// AlgoImpl.h
#ifndef ALGOIMPL_H_INCLUDED_
#define ALGOIMPL_H_INCLUDED_
class AlgoImpl
{
protected:
AlgoImpl();
~AlgoImpl();
void computeSomeImpl();
void computeMoreImpl();
};
#endif
// Algo.cpp
...
void Algo::computeSome()
{
computeSomeImpl();
}
void Algo::computeMore()
{
computeMoreImpl();
}
// Algo_SSE.cpp
AlgoImpl::AlgoImpl()
{
}
AlgoImpl::~AlgoImpl()
{
}
void AlgoImpl::computeSomeImpl()
{
}
void AlgoImpl::computeMoreImpl()
{
}
Pros:
the split is quite straightforward and easy to do
much cleaner than #ifdef-ing all over the place
still there is no "overhead" to my class - EBCO should kick in
the semantic of the class is much more cleaner at least comparing to the above
that is private inheritance == is implemented in terms of
the different files are compilable, can be included in the project
and selected via the build system
Cons:
I have three additional files for maintenance
if I do not have the specific optimized implementation yet for let's say
SSE I would have to duplicate some code from the plain(Scalar) C++ implementation file
I cannot fallback to the plain C++ implementation if nedded
3.Is basically method 2 but with virtual functions in the AlgoImpl class. That
would allow me to overcome the duplicate implementation of plain C++ code if needed
by providing an empty implementation in the base class and override in the derived
although I will have to disable that behavior when I actually implement the optimized
version. Also the virtual functions will bring some "overhead" to objects of my class.
4.A form of tag dispatching via enable_if<>
Pros:
the split is quite straightforward and easy to do
much cleaner than #ifdef ing all over the place
still there is no "overhead" to my class
will eliminate the need for different files for different implementations
Cons:
templates will be a bit more "cryptic" and seem to bring an unnecessary
overhead(at least for some people in some contexts)
if I do not have the specific optimized implementation yet for let's say
SSE I would have to duplicate some code from the plain(Scalar) C++ implementation
I cannot fallback to the plain C++ implementation if needed
What I couldn't figure out yet for any of the variants is how to properly and
cleanly fallback to the plain C++ implementation.
Also I don't want to over-engineer things and in that respect the first variant
seems the most "KISS" like even considering the disadvantages.
You could use a policy based approach with templates kind of like the way the standard library does for allocators, comparators and the like. Each implementation has a policy class which defines computeSome() and computeMore(). Your Algo class takes a policy as a parameter and defers to its implementation.
template <class policy_t>
class algo_with_policy_t {
policy_t policy_;
public:
algo_with_policy_t() { }
~algo_with_policy_t() { }
void process()
{
policy_.computeSome();
policy_.computeMore();
}
};
struct altivec_policy_t {
void computeSome();
void computeMore();
};
struct sse_policy_t {
void computeSome();
void computeMore();
};
struct scalar_policy_t {
void computeSome();
void computeMore();
};
// let user select exact implementation
typedef algo_with_policy_t<altivec_policy_t> algo_altivec_t;
typedef algo_with_policy_t<sse_policy_t> algo_sse_t;
typedef algo_with_policy_t<scalar_policy_t> algo_scalar_t;
// let user have default implementation
typedef
#if defined(ALTIVEC)
algo_altivec_t
#elif defined(SSE)
algo_sse_t
#else
algo_scalar_t
#endif
algo_default_t;
This lets you have all the different implementations defined within the same file (like solution 1) and compiled into the same program (unlike solution 1). It has no performance overheads (unlike virtual functions). You can either select the implementation at run time or get a default implementation chosen by the compile time configuration.
template <class algo_t>
void use_algo(algo_t algo)
{
algo.process();
}
void select_algo(bool use_scalar)
{
if (!use_scalar) {
use_algo(algo_default_t());
} else {
use_algo(algo_scalar_t());
}
}
As requested in the comments, here's a summary of what I did:
Set up policy_list helper template utility
This maintains a list of policies, and gives them a "runtime check" call before calling the first suitable implementaiton
#include <cassert>
template <typename P, typename N=void>
struct policy_list {
static void apply() {
if (P::runtime_check()) {
P::impl();
}
else {
N::apply();
}
}
};
template <typename P>
struct policy_list<P,void> {
static void apply() {
assert(P::runtime_check());
P::impl();
}
};
Set up specific policies
These policies implement a both a runtime test and an actual implementation of the algorithm in question. For my actual problem impl took another template parameter that specified what exactly it was they were implementing, here though the example assumes there is only one thing to be implemented. The runtime tests are cached in a static bool for some (e.g. the Altivec one I used) the test was really slow. For others (e.g. the OpenCL one) the test is actually "is this function pointer NULL?" after one attempt at setting it with dlsym().
#include <iostream>
// runtime SSE detection (That's another question!)
extern bool have_sse();
struct sse_policy {
static void impl() {
std::cout << "SSE" << std::endl;
}
static bool runtime_check() {
static bool result = have_sse();
// have_sse lives in another TU and does some cpuid asm stuff
return result;
}
};
// Runtime OpenCL detection
extern bool have_opencl();
struct opencl_policy {
static void impl() {
std::cout << "OpenCL" << std::endl;
}
static bool runtime_check() {
static bool result = have_opencl();
// have_opencl lives in another TU and does some LoadLibrary or dlopen()
return result;
}
};
struct basic_policy {
static void impl() {
std::cout << "Standard C++ policy" << std::endl;
}
static bool runtime_check() { return true; } // All implementations do this
};
Set per architecture policy_list
Trivial example sets one of two possible lists based on ARCH_HAS_SSE preprocessor macro. You might generate this from your build script, or use a series of typedefs, or hack support for "holes" in the policy_list that might be void on some architectures skipping straight to the next one, without trying to check for support. GCC sets some preprocessor macors for you that might help, e.g. __SSE2__.
#ifdef ARCH_HAS_SSE
typedef policy_list<opencl_policy,
policy_list<sse_policy,
policy_list<basic_policy
> > > active_policy;
#else
typedef policy_list<opencl_policy,
policy_list<basic_policy
> > active_policy;
#endif
You can use this to compile multiple variants on the same platform too, e.g. and SSE and no-SSE binary on x86.
Use the policy list
Fairly straightforward, call the apply() static method on the policy_list. Trust that it will call the impl() method on the first policy that passes the runtime test.
int main() {
active_policy::apply();
}
If you take the "per operation template" approach I mentioned earlier it might be something more like:
int main() {
Matrix m1, m2;
Vector v1;
active_policy::apply<matrix_mult_t>(m1, m2);
active_policy::apply<vector_mult_t>(m1, v1);
}
In that case you end up making your Matrix and Vector types aware of the policy_list in order that they can decide how/where to store the data. You can also use heuristics for this too, e.g. "small vector/matrix lives in main memory no matter what" and make the runtime_check() or another function test the appropriateness of a particular approach to a given implementation for a specific instance.
I also had a custom allocator for containers, which produced suitably aligned memory always on any SSE/Altivec enabled build, regardless of if the specific machine had support for Altivec. It was just easier that way, although it could be a typedef in a given policy and you always assume that the highest priority policy has the strictest allocator needs.
Example have_altivec():
I've included a sample have_altivec() implementation for completeness, simply because it's the shortest and therefore most appropriate for posting here. The x86/x86_64 CPUID one is messy because you have to support the compiler specific ways of writing inline ASM. The OpenCL one is messy because we check some of the implementation limits and extensions too.
#if HAVE_SETJMP && !(defined(__APPLE__) && defined(__MACH__))
jmp_buf jmpbuf;
void illegal_instruction(int sig) {
// Bad in general - https://www.securecoding.cert.org/confluence/display/seccode/SIG32-C.+Do+not+call+longjmp%28%29+from+inside+a+signal+handler
// But actually Ok on this platform in this scenario
longjmp(jmpbuf, 1);
}
#endif
bool have_altivec()
{
volatile sig_atomic_t altivec = 0;
#ifdef __APPLE__
int selectors[2] = { CTL_HW, HW_VECTORUNIT };
int hasVectorUnit = 0;
size_t length = sizeof(hasVectorUnit);
int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
if (0 == error)
altivec = (hasVectorUnit != 0);
#elif HAVE_SETJMP_H
void (*handler) (int sig);
handler = signal(SIGILL, illegal_instruction);
if (setjmp(jmpbuf) == 0) {
asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
altivec = 1;
}
signal(SIGILL, handler);
#endif
return altivec;
}
Conclusion
Basically you pay no penalty for platforms that can never support an implementation (the compiler generates no code for them) and only a small penalty (potentially just a very predictable by the CPU test/jmp pair if your compiler is half-decent at optimising) for platforms that could support something but don't. You pay no extra cost for platforms that the first choice implementation runs on. The details of the runtime tests vary between the technology in question.
If the virtual function overhead is acceptable, option 3 plus a few ifdefs seems a good compromise IMO. There are two variations that you could consider: one with abstract base class, and the other with the plain C implementation as the base class.
Having the C implementation as the base class lets you gradually add the vector optimized versions, falling back on the non-vectorized versions as you please, using an abstract interface would be a little cleaner to read.
Also, having separate C++ and vectorized versions of your class let you easily write unit tests that
Ensure that the vectorized code is giving the right result (easy to mess this up, and vector floating registers can have different precision than FPU, causing different results)
Compare the performance of the C++ vs the vectorized. It's often good to make sure the vectorized code is actually doing you any good. Compilers can generate very tight C++ code that sometimes does as well or better than vectorized code.
Here's one with the plain-c++ implementations as the base class. Adding an abstract interface would just add a common base class to all three of these:
// Algo.h:
class Algo_Impl // Default Plain C++ implementation
{
public:
virtual ComputeSome();
virtual ComputeSomeMore();
...
};
// Algo_SSE.h:
class Algo_Impl_SSE : public Algo_Impl // SSE
{
public:
virtual ComputeSome();
virtual ComputeSomeMore();
...
};
// Algo_Altivec.h:
class Algo_Impl_Altivec : public Algo_Impl // Altivec implementation
{
public:
virtual ComputeSome();
virtual ComputeSomeMore();
...
};
// Client.cpp:
Algo_Impl *myAlgo = 0;
#ifdef SSE
myAlgo = new Algo_Impl_SSE;
#elseif defined(ALTIVEC)
myAlgo = new Algo_Impl_Altivec;
#else
myAlgo = new Algo_Impl_Default;
#endif
...
You may consider to employ adapter patterns. There are a few types of adapters and it's quite an extensible concept. Here is an interesting article Structural Patterns: Adapter and Façade
that discusses very similar matter to the one in your question - the Accelerate framework as an example of the Adapter patter.
I think it is a good idea to discuss a solution on the level of design patterns without focusing on implementation detail like C++ language. Once you decide that the adapter states the right solutiojn for you, you can look for variants specific to your implemementation. For example, in C++ world there is known adapter variant called generic adapter pattern.
This isn't really a whole answer: just a variant on one of your existing options. In option 1 you've assumed that you include algo_altivec.cpp &c. into algo.cpp, but you don't have to do this. You could omit algo.cpp entirely, and have your build system decide which of algo_altivec.cpp, algo_sse.cpp, &c. to build. You'd have to do something like this anyway whichever option you use, since each platform can't compile every implementation; my suggestion is only that whichever option you choose, instead of having #if ALTIVEC_ENABLED everywhere in the source, where ALTIVEC_ENABLED is set from the build system, you just have the build system decide directly whether to compile algo_altivec.cpp .
This is a bit trickier to achieve in MSVC than make, scons, &c., but still possible. It's commonplace to switch in a whole directory rather than individual source files; that is, instead of algo_altivec.cpp and friends, you'd have platform/altivec/algo.cpp, platform/sse/algo.cpp, and so one. This way, when you have a second algorithm you need platform-specific implementations for, you can just add the extra source file to each directory.
Although my suggestion's mainly intended to be a variant of option 1, you can combine this with any of your options, to let you decide in the build system and at runtime which options to offer. In that case, though, you'll probably need implementation-specific header files too.
In order to hide the implementation details you may just use an abstract interface with static creator and provide three 3 implementation classes:
// --------------------- Algo.h ---------------------
#pragma once
typedef boost::shared_ptr<class Algo> AlgoPtr;
class Algo
{
public:
static AlgoPtr Create(std::string type);
~Algo();
void process();
protected:
virtual void computeSome() = 0;
virtual void computeMore() = 0;
};
// --------------------- Algo.cpp ---------------------
class PlainAlgo: public Algo { ... };
class AltivecAlgo: public Algo { ... };
class SSEAlgo: public Algo { ... };
static AlgoPtr Algo::Create(std::string type) { /* Factory implementation */ }
Please note, that since PlainAlgo, AlivecAlgo and SSEAlgo classes are defined in Algo.cpp, they are only seen from this compilation unit and therefore the implementation details hidden from the outside world.
Here is how one can use your class then:
AlgoPtr algo = Algo::Create("SSE");
algo->Process();
It seems to me that your first strategy, with separate C++ files and #including the specific implementation, is the simplest and cleanest. I would only add some comments to your Algo.cpp indicating which methods are in the #included files.
e.g.
// Algo.cpp
#include "Algo.h"
Algo::Algo() { }
Algo::~Algo() { }
void Algo::process()
{
computeSome();
computeMore();
}
// The following methods are implemented in separate,
// platform-specific files.
// void Algo::computeSome()
// void Algo::computeMore()
#if defined(ALTIVEC)
#include "Algo_Altivec.cpp"
#elif defined(SSE)
#include "Algo_SSE.cpp"
#else
#include "Algo_Scalar.cpp"
#endif
Policy-like templates (mixins) are fine until the requirement to fall back to default implementation. It's runtime opeation and should be handled by runtime polymorphism. Strategy pattern can handle this fine.
There's one drawback of this approach: Strategy-like algorithm implemented cannot be inlined. Such inlining can provide reasonable performance improvement in rare cases. If this is an issue you'll need to cover higher-level logic by Strategy.

C++ way of dependency injection - Templates or virtual methods?

I wonder what is the C++ way of using dependency injection? Is that using templates or polymorphic classes? Consider the following code,
class AbstractReader
{
public:
virtual void Read() = 0;
};
class XMLReader : public AbstractReader
{
public:
void Read() { std::cout << "Reading with a XML reader" << std::endl; }
};
class TextFileReader : public AbstractReader
{
public:
void Read() { std::cout << "Reading with a Text file reader" << std::endl; }
};
class Parser
{
public:
Parser(AbstractReader* p_reader) : reader(p_reader) { }
void StartParsing() { reader->Read();
// other parsing logic
}
private:
AbstractReader* reader;
};
template<class T>
class GenericParser
{
public:
GenericParser(T* p_reader) : reader(p_reader) { }
void StartParsing()
{
reader->Read();
}
private:
T* reader;
};
1 - Which is the best method? GenericParser or Parser? I know if it is GenericParser, inheritance can be removed.
2 - If templates is the way to go, is it OK to write all the code in header files? I have seen many classes using templates writes all the code in header files rather than .h/.cpp combination. Is there any problems in doing so, something like inlining etc?
Any thoughts?
You don't have a free choice in this, based on how you want to structure your code or header files. The answer is dictated to you by the requirements of your application.
It depends on whether the coupling can be be decided at compile time or must be delayed until runtime.
If the coupling between a component and its dependencies is decided permanently at compile time, you can use templates. The compiler will then be able to perform inlining.
If however the coupling needs to be decided at runtime (e.g. the user chooses which other component will supply the dependency, perhaps through a configuration file) then you can't use templates for that, and you must use a runtime polymorphic mechanism. If so, your choices include virtual functions, function pointers or std::function.
I personally prefer to use the template solution if I know the type of the reader at the compile time itself as I feel there is no run time decision to be taken here hence the polymorphism will be of no use. As far as writing the templates in header files is concerned, you have to do that to avoid getting the linker error. This is because if you write the template method in a cpp, the compiler will not be able to instantiate the template class and hence the linker will give error. Although, a couple of workarounds exist, most of the template code is written in header files.
As to 1. "Best" is relative. Both methods have their pluses and minuses. Templates offer raw speed, but more code is inevitably inlined (yielding more coupling), and the error messages are hard to read. Inheritance is slower and makes objects larger, but it doesn't require inlining (less coupled). It also has relatively better error messages.
For a small library, coupling matters less, and templates can be a good choice. However, as complexity of your library increases, you need to move towards a less coupled approach. If you are unsure of how large your library will grow, or don't need the speed templating would provide (or don't want to deal with the error messages), go with inheritance.
My answer to 2 follows up on 1. Inlining is needed for some consumer templates, therefor requiring code placed in the header. It's a question of coupling. Inlining increases coupling between components and can drastically increase compile times; avoid it unless you want the speed and are sure your library will remain small.
GenericParser or Parser?
Depends on the rest of the code, the problem with the generic parser is that class you are going to inject also has to be a template.
But there is a 3rd more generic way ... boost::function and boost::lambda. All you have to ask for is a function with the correct (from the view of the user of the class) return type and parameters. boost::function< void ()> reader = bind( &TextFile::read, reader );
Now the user class is independent of the reader class and doesn't have to be a template.
class User
{
const boost::function< void ()>& reader;
public:
void setReader( const boost::function< void ()>& reader )
: reader(reader) {
}
};
Writes all the code in header files rather than .h/.cpp combination.
That is called the seperation model is there is only one compiler that supports it (Comeau compiler). Start reading "Export" Restriction part 1 and "Export" Restrictions part 2
#CiscoIPPhone Comment on: the problem with the generic parser is that class you are going to inject also has to be a template.
template<class T>
class GenericParser
{
public:
GenericParser(T* p_reader) : reader(p_reader) { }
void StartParsing()
{
reader->Read();
}
private:
T* reader;
};
// Now you have a GeniricParser Interface but your Parser is only usable for
// TextFileReader
class Parser
{
public:
Parser( GenericParser<TextFileReader> p_reader) : reader(p_reader) { }
void StartParsing() {
reader->Read();
}
private:
GenericParser<RealParser> reader;
};
//Solution is to make Parser also a template class
template<class T>
class Parser
{
public:
Parser( GenericParser<T> p_reader) : reader(p_reader) { }
void StartParsing() {
reader->Read();
}
private:
GenericParser<T> reader;
};