(Note: Only the introduction is linux specific.)
On Linux there are two functions called strerror_r. One can choose
between those function using appropriate preprocessor flags. The problem
is that the functions have different return types which is why I tried
to wrap the handling code in another C++ function. I wanted to hide the
distinction using templates.
The idea is to create template specializations for each implementation
and let the compiler decide which one to pick. For some reason g++ 4.5.3
always seems to instantiate both methods and I don't know why.
Here is what I think should happen:
1. The compiler evaluates Equals<GNU_type, T> in line 83
2. The compiler instantiates Call<true> (on *my* system is true).
Call<false> is not instantiated.
3. The compiler instantiates Strerror_r<GNU_type> because of 2.). Also
because of 2.), Strerror_r<Posix_type> is never instantiated.
4. The compiler sees fitting returns types in line 19, the mismatch in
line 36 is ignored.
Where is my mistake?
Compiler: g++ 4.5.3
Error Message:
map.cpp: In member function ‘int Strerror_r<int (*)(int, char*, long
unsigned int)>::posix(int, char*, size_t)’:
map.cpp:36:40: error: invalid conversion from ‘char*’ to ‘int’
(On my system the GNU's strerror_r version is used (char* return type))
Code:
#include <cstdio>
#include <cerrno>
#include <cstring> // strerror_r
typedef char* (*Gnu_strerror_r_type)(int, char*, size_t);
typedef int (*Posix_strerror_r_type)(int, char*, size_t);
template<typename Fun>
struct Strerror_r;
template<>
struct Strerror_r<Gnu_strerror_r_type>
{
int gnu(int error, char* buffer, size_t size)
{
char* p( strerror_r(error, buffer, size) ); // line 19
if( !p || p == buffer )
return 0;
strncpy(buffer, p, size-1);
buffer[size-1] = 0;
return 0;
}
};
template<>
struct Strerror_r<Posix_strerror_r_type>
{
// Why is this instantiated???
int posix(int error, char* buffer, size_t size)
{
return strerror_r(error, buffer, size); // Line 36 here
}
};
template<bool value>
struct Call;
template<>
struct Call<true>
{
Strerror_r<Gnu_strerror_r_type> s;
int execute(int e, char* p, size_t sz) { return s.gnu(e,p,sz); }
};
template<>
struct Call<false>
{
Strerror_r<Posix_strerror_r_type> s;
int execute(int e, char* p, size_t sz) { return s.posix(e,p,sz); }
};
template<typename T, typename U>
struct Equals
{
static const bool value = false;
};
template<typename T>
struct Equals<T, T>
{
static const bool value = true;
};
template<typename T>
int my_strerror_r_impl(
T, int error, char* buffer, size_t size)
{
Call<Equals<Gnu_strerror_r_type, T>::value> c; // line 83
return c.execute(error, buffer, size);
}
int my_strerror_r(int error, char* buffer, size_t size)
{
return my_strerror_r_impl(&strerror_r, error, buffer, size);
}
int main()
{
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
if( my_strerror_r(ENOSYS, buffer, sizeof(buffer)) < 0 )
return 1;
std::printf( "Message: '%s'\n", buffer );
}
--
[ See
http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]