Is it okay to use different implementation files to achieve polymorphism? - c++

In the case where there are multiple desired implementations for a given interface, but where the specific implementation desired is known before compile time, is it wrong simply to direct the make file to different implementation files for the same header?
For example, if have a program defining a car (Car.h)
// Car.h
class Car {
public:
string WhatCarAmI();
}
and at build time we know whether we want it to be a Ferrari or a Fiat, to give each either of the corresponding files:
// Ferrari.cpp
#include "Car.h"
string Car::WhatCarAmI() { return "Ferrari"; }
whilst for the other case (unsurprisingly)
// Fiat.cpp
#include "Car.h"
string Car::WhatCarAmI() { return "Fiat"; }
Now, I am aware that I could make both Fiat and Ferrari derived objects of Car and at runtime pick which I would like to build. Similarly, I could templatize it and make the compiler pick at compile time which to build. However, in this case the two implementations both refer to separate projects which should never intersect.
Given that, is it wrong to do what I propose and simply to select the correct .cpp in the makefile for the given project? What is the best way to do this?

Implementation
As this is static polymorphism, the Curiously Recurring Template Pattern is probably vastly more idiomatic than swapping a cpp file - which seems pretty hacky. CRTP seems to be required if you want to let multiple implementations coexist within one project, while being easy to use with an enforced single-implementation build system. I'd say its well-documented nature and ability to do both (since you never know what you'll need later) give it the edge.
In brief, CRTP looks a little like this:
template<typename T_Derived>
class Car {
public:
std::string getName() const
{
// compile-time cast to derived - trivially inlined
return static_cast<T_Derived const *>(this)->getName();
}
// and same for other functions...
int getResult()
{
return static_cast<T_Derived *>(this)->getResult();
}
void playSoundEffect()
{
static_cast<T_Derived *>(this)->playSoundEffect();
}
};
class Fiat: public Car<Fiat> {
public:
// Shadow the base's function, which calls this:
std::string getName() const
{
return "Fiat";
}
int getResult()
{
// Do cool stuff in your car
return 42;
}
void playSoundEffect()
{
std::cout << "varooooooom" << std::endl;
}
};
(I've previously prefixed derived implementation functions with d_, but I'm not sure this gains anything; in fact, it probably increases ambiguity...)
To understand what's really going on in the CRTP - it's simple once you get it! - there are plenty of guides around. You'll probably find many variations on this, and pick the one you like best.
Compile-time selection of implementation
To get back to the other aspect, if you do want to restrict to one of the implementations at compile-time, then you could use some preprocessor macro(s) to enforce the derived type, e.g.:
g++ -DMY_CAR_TYPE=Fiat
and later
// #include "see_below.hpp"
#include <iostream>
int main(int, char**)
{
Car<MY_CAR_TYPE> myCar;
// Do stuff with your car
std::cout << myCar.getName();
myCar.playSoundEffect();
return myCar.getResult();
}
You could either declare all Car variants in a single header and #include that, or use something like the methods discussed in these threads - Generate include file name in a macro / Dynamic #include based on macro definition - to generate the #include from the same -D macro.

Choosing a .cpp file at compile time is OK and perfectly reasonable... if the ignored .cpp file would not compile. This is one way to choose a platform specific implementation.
But in general - when possible (such as in your trivial example case) - it's better to use templates to achieve static polymorphism. If you need to make a choice at compile time, use a preprocessor macro.
If the two implementations refer to separate projects which should never intersect but still are implementations for a given interface, I would recommend to extract that interface as a separate "project". That way the separate projects are not directly related to each other, even though they both depend on the third project which provides the interface.

In your use case I think it would be best to use ifdef-blocks. This will be checked before compilation! This method is also sometimes used to distinct between different platforms for the same code.
// Car.cpp
#include "Car.h"
#define FERRARI
//#define FIAT
#ifdef FERRARI
string Car::WhatCarAmI() { return "Ferrari"; }
#endif
#ifdef FIAT
string Car::WhatCarAmI() { return "Fiat"; }
#endif
In these code the compiler will ignore the ifdef-block of fiat, because only FERRARI is defined. This way you can still use methods you want to have for both cars. Everything you want different, you can put in ifdefs and simply swap out the defines.
Actually instead of swapping out the defines, you'd leave your code alone and
provide the definitions on the GCC command line using the -D build switch,
depending on what build configuration were selected.

Related

Ensure at compile time that a method is called in exactly one place

I am curious about whether it is possible to ensure at compile time that a method is called in exactly one place.
Note that it is OK if the function is called more than once (e.g. in a loop) - but it should not be called in two separate loops.
This can be broken into two parts, I am also interested in solutions that cover either part:
(a) ensure a method is called in at least one place
(b) ensure a method is called in at most one place
I have full control over the structure of the code, and different idioms that achieve the same idea are welcome.
// class.h
class MyClass {
public:
void my_method();
}
The following should not compile (never called)
#include "class.h"
int main() {
MyClass my_class;
}
The following should not compile (called in more than one place)
#include "class.h"
int main() {
MyClass my_class;
my_class.my_method();
while(true) {
my_class.my_method();
}
}
The following should compile (called in exactly one place):
#include "class.h"
int main() {
MyClass my_class;
while(true) {
my_class.my_method();
}
}
Low Tech Approach:
Since you have control over the code structure (which includes the build system, I assume), here is a low tech solution:
make the function name sufficiently unique
grep for the function name in your code. You are expecting it twice (assuming that you declaration and definition are colocated):
Once in the header
Once at the single call site
Alternatively:
If you really, really, really want to solve it with C++, then you could try
Use a compile time counter to figure out the number of uses within a compilation units
Make sure that the function would violate ODR if the header is included in multiple compilation units.
However, compile time counters are black magic (says I, and I really like TMP), and forcing ODR violations for this purpose seems like similar voodoo (at least you would require a test case that fails to link).
But seriously:
Don't do this. Whatever you do, it can be perverted with almost no effort by a wrapper function:
auto call_my_method(MyClass& o)
{
return o.my_method();
}
MyClass::my_method() is called only in the wrapper. Everybody else just calls the wrapper which is probably even inlined by the compiler.
As others suggested: It might be much more helpful if you would explain what you are trying to do.
Here's a rough idea that may work (too long for a comment - but incomplete for a good SO answer).
You may be able to achieve this by counting/checking template instantiations.
Templates are instantiated only upon use.
Similarly, template method/function bodies are not parsed nor compiled or linked (beyond ensuring valid syntax) if they are never called. This means that any instantiations within their bodies are not made).
You may be able to create a template that maintains some global instantiation count and static assert on that (or some other TMP mechanism to check past instantiations).
There is a partial solution to this question using the C preprocessor and GNU inline assembly:
Header file a.h:
struct A {
// Do not call this method directly, use the macro below to call it
int _method_vUcaJB5NKSD3upQ(int i, int j);
};
// Use inline assembly to ensure that this macro is used at most once
#define method_vUcaJB5NKSD3upQ(args...) \
_method_vUcaJB5NKSD3upQ(args); \
asm (".global once_vUcaJB5NKSD3upQ; once_vUcaJB5NKSD3upQ:");
Implementation file a.cc:
#include <iostream>
#include "a.h"
int A::_method_vUcaJB5NKSD3upQ(int i, int j) { return i+j+5; }
// Ensure that the macro is used at least once
extern "C" const char once_vUcaJB5NKSD3upQ;
static const char get_vUcaJB5NKSD3upQ = once_vUcaJB5NKSD3upQ;
int main() {
A a;
for(int i=0; i<7; i++) {
// Use a separate statement to call the method
// (terminated by a semicolon, it cannot be a sub-expression)
auto x = a.method_vUcaJB5NKSD3upQ(2, 3);
std::cout << x << std::endl;
}
return 0;
}
This solution is partial in the sense that it does not prevent the program to call the method beginning with the underscore directly without using the wrapper macro.
Use a constexpr counter. There is an implementation in another question

Why doesn't C++ allow adding new methods to classes?

It seems like a rather arbitrary limitation.
Aren't regular methods just like C functions with a parameter that points to the instance?
If so I don't see why adding new methods should force me to recompile the rest of my class. Why not allow adding methods via a separate amendment header and a separate amendment implementation.
Consider this example
// in some header
struct X
{
float func(float);
};
// and in another source file
void caller()
{
X x;
std::cout << x.func(2); // will call X:func(float)
}
Now let's say we decide to add a new version of func() that accepts an int.
// in some header
struct X
{
float func(float);
void func(int);
};
// and in another source file
void caller()
{
X x;
std::cout << x.func(2);
}
If the caller() function is not recompiled, there is no way to register that the function it is calling has changed - it will keep calling X::func(float) in the build.
Then - possibly months (or in large systems, years) after the fact - another developer makes a completely unrelated change to one of the functions in the same source file as caller(). Hence that source file gets rebuilt ... finally. Suddenly that person finds that caller() won't compile - with error messages that have nothing whatsoever to do with changes of code he or she is implementing.
All this happens when the offender - the programmer who introduced the new member functions but didn't trigger a recompile and rebuild - is nowhere to be seen.
The developer left behind is left to fix the mess. With no information about what actually caused the problem, why it was working yesterday but not today, no real clue as to how to fix it properly .... but still the one who will be held responsible.
This is just one of many problems that the "arbitrary limitation" in C++ will prevent.
A couple of things comes to my mind. On one hand you need to declare the scope of the method, I presume that's the reason why you are allowed to add new operators in the way that you are suggesting.
On the other hand, you have a problem with inheritance. The compiler need to know all the virtual methods in order to include them in the vtable.
As deviantfan said, it's no real problem really (assuming you want to add a regular (nonvirtual) method).
$ for file in X.hh X.cc X-1.hh X-1.cc main.cc; do echo -e "\n//--------------//$file"; cat "$file"; done
//--------------//X.hh
//X.hh
struct X {
int foo(int);
};
//--------------//X.cc
//X.cc (available as X.o)
#include "X.hh"
int X::foo(int a){ return a+1; }
//--------------//X-1.hh
//X-1.hh
//copy X.hh and amend it
struct X {
int foo(int);
int bar(int);
};
//--------------//X-1.cc
//X-1.cc
#include "X-1.hh"
int X::bar(int a){ return a+2; }
//--------------//main.cc
//main.cc
#include "X-1.hh"
//^the latest definition
#include <iostream>
int main(){
using namespace std;
X x;
cout << x.foo(1) << endl;
cout << x.bar(1) << endl;
And now the building part:
$ make {X,X-1,main}.o
$ g++ {X,X-1,main}.o #links correctly!
$ ./a.out
2
3
Works even if the methods access class/struct variables.
TL;DR:
If you use a build system that uses depend files that track #includes, you can make --assume-old a header (or touch --date='10 minutes ago' changed_header.hh) that only changed by means of trivial method additions (no overloads or virtuals), as all old object files that depended on the old subset of the class's instance methods won't need to be recompiled.
Also, as AliciaBytes points out, there's a proposal for a http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf
that basically allows freestanding functions to be invoked via the dot syntax, so that's basically tantamount to reopening a class for trivial function additions.
Overloaded functions aren't really a problem as you would always #include a particular representation of a class (or the same class + a particular set of dot-syntax mappable free-standing functions) and you could have different versions of the same class (equivalent to having one class + different sets of dot-syntax mappable free-standing functions). (unlike virtual functions, because of vtables and vtable pointers in object instances).

Static member initialization using CRTP in separate library

After digging the web, I found some reference to a powerful pattern which exploits CRTP to allow instantiation at run-time of static members:
C++: Compiling unused classes
Initialization class for other classes - C++
And so on.
The proposed approach works well, unless such class hierarchy is placed into an external library.
Doing so, run-time initialization no more works, unless I manually #include somewhere the header file of derived classes. However, this defeats my main purpose - having the change to add new commands to my application without the need of changing other source files.
Some code, hoping it helps:
class CAction
{
protected:
// some non relevant stuff
public:
// some other public API
CAction(void) {}
virtual ~CAction(void) {}
virtual std::wstring Name() const = 0;
};
template <class TAction>
class CCRTPAction : public CAction
{
public:
static bool m_bForceRegistration;
CCRTPAction(void) { m_bForceRegistration; }
~CCRTPAction(void) { }
static bool init() {
CActionManager::Instance()->Add(std::shared_ptr<CAction>(new TAction));
return true;
}
};
template<class TAction> bool CCRTPAction<TAction>::m_bForceRegistration = CCRTPAction<TAction>::init();
Implementations being done this way:
class CDummyAction : public CCRTPAction<CDummyAction>
{
public:
CDummyAction() { }
~CDummyAction() { }
std::wstring Name() const { return L"Dummy"; }
};
Finally, here is the container class API:
class CActionManager
{
private:
CActionManager(void);
~CActionManager(void);
std::vector<std::shared_ptr<CAction>> m_vActions;
static CActionManager* instance;
public:
void Add(std::shared_ptr<CAction>& Action);
const std::vector<std::shared_ptr<CAction>>& AvailableActions() const;
static CActionManager* Instance() {
if (nullptr == instance) {
instance = new CActionManager();
}
return instance;
}
};
Everything works fine in a single project solution. However, if I place the above code in a separate .lib, the magic somehow breaks and the implementation classes (DummyAction and so on) are no longer instantiated.
I see that #include "DummyAction.h" somewhere, either in my library or in the main project makes things work, but
For our project, it is mandatory that adding Actions does not require changes in other files.
I don't really understand what's happening behind the scene, and this makes me uncomfortable. I really hate depending on solutions I don't fully master, since a bug could get out anywhere, anytime, possibly one day before shipping our software to the customer :)
Even stranger, putting the #include directive but not defining constructor/destructor in the header file still breaks the magic.
Thanks all for attention. I really hope someone is able to shed some light...
I can describe the cause of the problem; unfortunately I can't offer a solution.
The problem is that initialisation of a variable with static storage duration may be deferred until any time before the first use of something defined in the same translation unit. If your program never uses anything in the same translation unit as CCRTPAction<CDummyAction>::m_bForceRegistration, then that variable may never be initialised.
As you found, including the header in the translation unit that defines main will force it to be initialised at some point before the start of main; but of course that solution won't meet your first requirement. My usual solution to the problems of initialising static data across multiple translation units is to avoid static data altogether (and the Singleton anti-pattern doubly so, although that's the least of your problems here).
As explained in Mike's answer, the compiler determines that the static member CCRTPAction<CDummyAction>::m_bForceRegistration is never used, and therefore does not need to be initialised.
The problem you're trying to solve is to initialise a set of 'plugin' modules without having to #include their code in a central location. CTRP and templates will not help you here. I'm not aware of a (portable) way in C++ to generate code to initialise a set of plugin modules that are not referenced from main().
If you're willing to make the (reasonable) concession of having to list the plugin modules in a central location (without including their headers), there's a simple solution. I believe this is one of those extremely rare cases where a function-scope extern declaration is useful. You may consider this a dirty hack, but when there's no other way, a dirty hack becomes an elegant solution ;).
This code compiles to the main executable:
core/module.h
template<void (*init)()>
struct Module
{
Module()
{
init();
}
};
// generates: extern void initDummy(); Module<initDummy> DummyInstance
#define MODULE_INSTANCE(name) \
extern void init ## name(); \
Module<init ## name> name ## Instance
core/action.h
struct Action // an abstract action
{
};
void addAction(Action& action); // adds the abstract action to a list
main.cpp
#include "core/module.h"
int main()
{
MODULE_INSTANCE(Dummy);
}
This code implements the Dummy module and compiles to a separate library:
dummy/action.h
#include "core/action.h"
struct DummyAction : Action // a concrete action
{
};
dummy/init.cpp
#include "action.h"
void initDummy()
{
addAction(*new DummyAction());
}
If you wanted to go further (this part is not portable) you could write a separate program to generate a list of MODULE_INSTANCE calls, one for each module in your application, and output a generated header file:
generated/init.h
#include "core/module.h"
#define MODULE_INSTANCES \
MODULE_INSTANCE(Module1); \
MODULE_INSTANCE(Module2); \
MODULE_INSTANCE(Module3);
Add this as a pre-build step, and core/main.cpp becomes:
#include "generated/init.h"
int main()
{
MODULE_INSTANCES
}
If you later decide to load some or all of these modules dynamically, you can use exactly the same pattern to dynamically load, initialise and unload a dll. Please note that the following example is windows-specific, untested and does not handle errors:
core/dynamicmodule.h
struct DynamicModule
{
HMODULE dll;
DynamicModule(const char* filename, const char* init)
{
dll = LoadLibrary(filename);
FARPROC function = GetProcAddress(dll, init);
function();
}
~DynamicModule()
{
FreeLibrary(dll);
}
};
#define DYNAMICMODULE_INSTANCE(name) \
DynamicModule name ## Instance = DynamicModule(#name ".dll", "init" #name)
As Mike Seymour stated the static template stuff will not give you the dynamic loading facilities you want. You could load your modules dynamically as plug ins. Put dlls containing an action each into the working directory of the application and load these dlls dynamically at run-time. This way you will not have to change your source code in order to use different or new implementations of CAction.
Some frameworks make it easy to load custom plug ins, for example Qt.

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.

What am I not getting about this abstract class implementation?

PREFACE: I'm relatively inexperienced in C++ so this very well could be a Day 1 n00b question.
I'm working on something whose long term goal is to be portable across multiple operating systems. I have the following files:
Utilities.h
#include <string>
class Utilities
{
public:
Utilities() { };
virtual ~Utilities() { };
virtual std::string ParseString(std::string const& RawString) = 0;
};
UtilitiesWin.h (for the Windows class/implementation)
#include <string>
#include "Utilities.h"
class UtilitiesWin : public Utilities
{
public:
UtilitiesWin() { };
virtual ~UtilitiesWin() { };
virtual std::string ParseString(std::string const& RawString);
};
UtilitiesWin.cpp
#include <string>
#include "UtilitiesWin.h"
std::string UtilitiesWin::ParseString(std::string const& RawString)
{
// Magic happens here!
// I'll put in a line of code to make it seem valid
return "";
}
So then elsewhere in my code I have this
#include <string>
#include "Utilities.h"
void SomeProgram::SomeMethod()
{
Utilities *u = new Utilities();
StringData = u->ParseString(StringData); // StringData defined elsewhere
}
The compiler (Visual Studio 2008) is dying on the instance declaration
c:\somepath\somecode.cpp(3) : error C2259: 'Utilities' : cannot instantiate abstract class
due to following members:
'std::string Utilities::ParseString(const std::string &)' : is abstract
c:\somepath\utilities.h(9) : see declaration of 'Utilities::ParseString'
So in this case what I'm wanting to do is use the abstract class (Utilities) like an interface and have it know to go to the implemented version (UtilitiesWin).
Obviously I'm doing something wrong but I'm not sure what. It occurs to me as I'm writing this that there's probably a crucial connection between the UtilitiesWin implementation of the Utilities abstract class that I've missed, but I'm not sure where. I mean, the following works
#include <string>
#include "UtilitiesWin.h"
void SomeProgram::SomeMethod()
{
Utilities *u = new UtilitiesWin();
StringData = u->ParseString(StringData); // StringData defined elsewhere
}
but it means I'd have to conditionally go through the different versions later (i.e., UtilitiesMac(), UtilitiesLinux(), etc.)
What have I missed here?
Utilities *u = new Utilities();
tells the compiler to make a new instance of the Utilities class; the fact that UtilitiesWin extends it isn't necessarily known and doesn't affect it. There could be lots of classes extending Utilities, but you told the compiler to make a new instance of Utilities, not those subclasses.
It sounds like you want to use the factory pattern, which is to make a static method in Utilities that returns a Utilities* that points to a particular instance:
static Utilities* Utilities::make(void) {return new UtilitiesWin();}
At some point you're going to have to instantiate a non-abstract subclass; there's no way around specifying UtilitiesWin at that point
You seem a bit confused as to what you want; you have to tell the computer at some stage which implementation of Utilities it is to use, but with the shape you've set out you only need to have
#ifdef windows
Utilities* u = new UtilitiesWin();
#endif
#ifdef spaceos3
Utilities* u = new UtilitiesSpaceOS3();
#endif
once in the program, and most of the source files can just call methods of u without knowing what kind of a u it is - which is I think what you were aiming at.
In C++ you cannot instantiate abstract classes, which is precisely what you are trying to do here:
Utilities *u = new Utilities();
It's very unclear to me why you would want to instantiate such a class, and what you would do with it if you could do so (which you can't). You cannot use an instantiation as an interface - the class definition provides that.
You are "getting" it right, you have to instantiate a concrete type. There are common solutions to this.
Yes, you have to make that decision which class to instantiate somewhere.
The implementation of that depends on the criteria for this decision: is it fixed for the binary? The same choice for each process? Or does it change for every instance of SomeProgram?
Fore the concrete classes you mention, the decision can probably be made at compile time, similar to what Tom suggests.
Second, SomeProgram should not make this choice itself. Rather the type or the instance should be configurable from the outside. The most simple approach is to pass the concrete instance to the constructor of SomeProgram:
class SomeProgram
{
private:
Utilities * m_utilities;
public:
Someprogram(Utilities * util) : m_utilities(util) {}
}
Note that SomeProgramonly "knows" the abstract class, none of the concrete classes.
For delayed construction, use a factory. If the utilities class should be injected as above, is expensive to create but isn't necessary most of the time, you would inject a factory instead: you pass a UtilityFactoryto the class, which SomeProgram can use to create the required instance on demand. The actual factory implementation decides the concrete class to chose. See Factory pattern for more.
If that's a common problem, look at Inversion of Control (IoC) - there are several library implementations out there that make that easier. It has become a buzzword in the wake of agressive unit testing, where replacing "real" implementations with mocks has to happen permanently. (I'm still waiting for a complete MockOS, though). I haven't worked on any application that seriously needed suhc a library in practice, though, and it is very likely overkill for your problem.