Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++98 compliant abs/fabs signature tester? (LONG)

0 views
Skip to first unread message

Daniel Spangenberg

unread,
Jan 14, 2003, 1:53:25 PM1/14/03
to
Hello, C++ community!

An earlier request of mine, concerning a standard C++ compliant way to
recognize a given function signature ("Determining existence of function
declarations"), returned some very thoughtful ideas especially from Rani
Sharoni and from Daveed Vandevoorde.
Although Daveeds proposal was so nicely short, it did not work on MSVC 6
(Compiler error, I think because of the template template argument) and
on the C++ Builder 5 or 6 (Did compile, but ALWAYS returned true - maybe
a compiler error?).

So I decided to use the ideas of Rani Sharoni, and created the following
C++ program, to determine on compile time the provided signatures of abs
and fabs function declarations of the headers <cstdlib> and <cmath>.

To my opinion, this program should check the existence of the expected
abs/fabs function declarations of the above mentioned standard headers
in a standard conforming way. The only non-conforming declaration I see,
is the assumed "C" linkage of printf, but I did not want to #include
<stdio.h> for this. Do you have another idea, to work around this
problem? (Of course, we could provide two translation units: One for
testing, one for output)

According to my reading of the C++98 standard, the functions of the C
standard library (in this case int abs(int) and double fabs(double) )
may be provided either as of external "C" or external "C++" linkage,
while the new abs/fabs signatures of C++ should be of "C++" linkage.

My question is: Do you think, that

1) my assumptions concerning linkage and varity of signatures are
correct?
2) given the 1st assumption as true, does the proposed program fulfill
these requirements?

If both assumptions are correct, I was wondering, why this program did
not return a successful result on the current .NET compiler 7.0 ;-))


Thanks for your reply,

Daniel Spangenberg

/* Tests for the existence of the declarations of different abs and fabs

signatures in the standard C++ headers <cstdlib> and <cmath>.

@author Daniel Spangenberg

The main ideas from this test routine came from Rani Sharoni -
Thanks!

Please note the following speciality of standard library functions
from the
C library in C++:

All pure C functions (int abs(int) or double fabs(double) in our
case) might
be either of extern "C" linkage or of "C++" linkage, which is
separately
tested below.
Corresponding to the current C++98 standard, this detail is
implementation
defined.

Attention: On modifying this file, you should NOT #include further
C++ or
C headers! If you want to change the test (e.g. to check the
<stdlib.h> and
the <math.h> header), you should REPLACE the given headers by other
ones!
*/

//---------------------------------------------------------------------------

#include <cstdlib>
#include <cmath>
//---------------------------------------------------------------------------

// Unique helper type, which guarantees the existence of at least one
// X abs(X)/X fabs(X) and at least one X std::abs(X)/X std::fabs(X)
declaration.

struct Unique;

Unique abs(Unique);
Unique fabs(Unique);

namespace std {

Unique abs(Unique);
Unique fabs(Unique);

}

// For testing the two possible extern "C" signatures:
extern "C" {

typedef int (*ExternCIntFunc)(int);
typedef double (*ExternCDoubleFunc)(double);

}


namespace Internal {

typedef char YesType;
typedef char (&NoType)[2];

// Extern "C++" signature tester:
template <typename T>
struct Checker
{
static YesType check(T (*)(T), int);

static NoType check(Unique (*)(Unique), ...);
};


// Extern "C" signature tester:
YesType checkCInt(ExternCIntFunc, int);
NoType checkCInt(Unique (*)(Unique), ...);

YesType checkCDouble(ExternCDoubleFunc, int);
NoType checkCDouble(Unique (*)(Unique), ...);

}


template <typename T>
struct AbsType
{
enum { has = sizeof(Internal::Checker<T>::check(::abs, 1)) ==
sizeof(Internal::YesType) };

enum { hasStd = sizeof(Internal::Checker<T>::check(::std::abs, 1))
== sizeof(Internal::YesType) };
};


template <typename T>
struct FAbsType
{
enum { has = sizeof(Internal::Checker<T>::check(::fabs, 1)) ==
sizeof(Internal::YesType) };

enum { hasStd = sizeof(Internal::Checker<T>::check(::std::fabs, 1))
== sizeof(Internal::YesType) };
};


// Compile time analysis for extern "C++" signatures:
enum { hasAbsInt = AbsType<int>::has };
enum { hasStdAbsInt = AbsType<int>::hasStd };

enum { hasAbsLong = AbsType<long>::has };
enum { hasStdAbsLong = AbsType<long>::hasStd };

enum { hasAbsFloat = AbsType<float>::has };
enum { hasStdAbsFloat = AbsType<float>::hasStd };

enum { hasAbsDouble = AbsType<double>::has };
enum { hasStdAbsDouble = AbsType<double>::hasStd };

enum { hasAbsLongDouble = AbsType<long double>::has };
enum { hasStdAbsLongDouble = AbsType<long double>::hasStd };

enum { hasFAbsFloat = FAbsType<float>::has };
enum { hasStdFAbsFloat = FAbsType<float>::hasStd };

enum { hasFAbsDouble = FAbsType<double>::has };
enum { hasStdFAbsDouble = FAbsType<double>::hasStd };

enum { hasFAbsLongDouble = FAbsType<long double>::has };
enum { hasStdFAbsLongDouble = FAbsType<long double>::hasStd };

// Compile time analysis for extern "C" signatures:
enum { hasCAbsInt = sizeof(Internal::checkCInt(::abs, 1)) ==
sizeof(Internal::YesType) };

enum { hasCStdAbsInt = sizeof(Internal::checkCInt(::std::abs, 1)) ==
sizeof(Internal::YesType) };

enum { hasCFAbsDouble = sizeof(Internal::checkCDouble(::fabs, 1)) ==
sizeof(Internal::YesType) };

enum { hasCStdFAbsDouble = sizeof(Internal::checkCDouble(::std::fabs,
1)) == sizeof(Internal::YesType) };


// We can not expect, that the printf function is declared in one of
the
// provided standard headers:
extern "C" int printf(char const*, ...);


int main()
{
printf("Checking combined headers <cstdlib> and <cmath>:\n\n");

printf("int abs(int) ? %d\n", hasAbsInt);
printf("int std::abs(int) ? %d\n", hasStdAbsInt);

printf("extern \"C\" int abs(int) ? %d\n", hasCAbsInt);
printf("extern \"C\" int std::abs(int) ? %d\n",
hasCStdAbsInt);

printf("long abs(long) ? %d\n", hasAbsLong);
printf("long std::abs(long) ? %d\n", hasStdAbsLong);

printf("float abs(float) ? %d\n", hasAbsFloat);
printf("float std::abs(float) ? %d\n",
hasStdAbsFloat);

printf("double abs(double) ? %d\n", hasAbsDouble);
printf("double std::abs(double) ? %d\n",
hasStdAbsDouble);

printf("long double abs(long double) ? %d\n",
hasAbsLongDouble);
printf("long double std::abs(long double) ? %d\n",
hasStdAbsLongDouble);

printf("float fabs(float) ? %d\n", hasFAbsFloat);
printf("float std::fabs(float) ? %d\n",
hasStdFAbsFloat);

printf("double fabs(double) ? %d\n", hasFAbsDouble);

printf("double std::fabs(double) ? %d\n",
hasStdFAbsDouble);

printf("extern \"C\" double fabs(double) ? %d\n",
hasCFAbsDouble);
printf("extern \"C\" double std::fabs(double) ? %d\n",
hasCStdFAbsDouble);

printf("long double fabs(long double) ? %d\n",
hasFAbsLongDouble);
printf("long double std::fabs(long double) ? %d\n",
hasStdFAbsLongDouble);

enum { result = (hasStdAbsInt || hasCStdAbsInt) &&
hasStdAbsLong &&
hasStdAbsFloat &&
hasStdAbsDouble &&
hasStdAbsLongDouble &&
hasStdFAbsFloat &&
(hasStdFAbsDouble || hasCStdFAbsDouble) &&
hasStdFAbsLongDouble };

printf("\n<cstdlib> and <cmath> are fully 'abs'/'fabs' compliant ?
%d\n", result);

return 0;
}
//---------------------------------------------------------------------------


[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Ruslan Abdikeev

unread,
Jan 15, 2003, 12:00:32 PM1/15/03
to
"Daniel Spangenberg" <d...@bdal.de> wrote in message
news:3E23CE08...@bdal.de...

> If both assumptions are correct, I was wondering, why this program did
> not return a successful result on the current .NET compiler 7.0 ;-))
>

Because you didn't enable the /Za switch (Disable Language Extensions).
In math.h, the section about abs() and fabs() overloads is #ifdefed
by _MSC_EXTENSIONS.
That is, they exist ONLY in strict mode.

If you disable language extensions, your code shows that
the MS VC++ 7 is standard compliant in the sense of abs/fabs signatures.

Sincerely,

Ruslan Abdikeev
Brainbench MVP for Visual C++
http://www.brainbench.com

0 new messages