Re: Using templates to wrap OS APIs
On 15 Okt., 10:12, Scott Meyers <smey...@aristeia.com> wrote:
Somewhere, I figure this has got to be a FAQ. But I don't know where.
I want to wrap OS-dependent code in an OS-independent API to shield
clients
from having to know that, e.g., what's called Sleep under Windows is
called
usleep under Linux. No problem, I can use ifdefs:
#ifdef WINDOWS
inline void sleepMilliseconds( unsigned int uMilliseconds )
{ Sleep( uMilliseconds ); }
#else
inline void sleepMilliseconds( unsigned int uMilliseconds )
{ usleep( 1000 * uMilliseconds ); }
#endif
Except the preprocessor is gross. I'd rather use templates:
struct Windows;
struct Linux;
template<typename OS> struct OSWrapper;
template<>
struct OSWrapper<Windows>
{
inline static void sleepMilliseconds( unsigned int uMilliseconds )
{ Sleep( uMilliseconds ); }
};
template<>
struct OSWrapper<Linux>
{
inline static void sleepMilliseconds( unsigned int uMilliseconds )
{ Sleep( uMilliseconds ); }
};
Unfortunately, this won't compile. Even with the appropriate
platform-specific #include directives, there is no Sleep on Linux and no
usleep on Windows, so one of the template specializations won't compile,
regardless of the platform on which I am compiling.
The names Sleep and usleep are non-dependent names in the template, hence
looked up prior to instantiation. If I could somehow make them dependent
names, they'd be looked up only after instantiation, which would be fine.
However, I can't make them dependent by prefixing the calls with "this->",
because the functions I'm in are static. I can't find a way to move them
into another class (thus allowing me to make the names dependent by
prefixing them with "OS::" in the general template) without facing the
same
name-lookup problem in whatever class I introduce.
Wrapping platform-dependent APIs has got to be a common C++ activity, and
it seems like templates should be well-suited to the job. Yet I keep
coming back to ifdefs. Can somebody please point out the error of my
ways?
I would try to get rid of the multi-configuration-implementation in a
single
header. In fact it is far much more easier to configure the build tool
to select
the proper directory for configuration-specific code. This way there
is no
need for any template code, because you client-header would just
declare
#include <os-config.h>
// implicitly include
// inline void sleepMilliseconds( unsigned int uMilliseconds )
// with the correct implementation
where depending on the build-tool configuration <os-config.h>
would now point either to
windows/os-config.h
or
linux/os-config.h
This way you have a much better encapsulation of system-specific
code. Each such header is independent from the sum of all
configurations you need to support.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]