C99 fallback with disable_if

J

Jonathan Lee

Hey all,
I'm trying to provide fallbacks for a C99 function (hypot in cmath)
using "disable_if". Something like, "if hypot(double, double) is
not provided by cmath, use this instead"

It isn't working. Anyone know how I can wrangle this? Below is my
attempt.

Thanks
--Jonathan

//#include <cmath>
#include <iostream>

using std::cout;
using std::endl;

template<typename T>
struct temp {
typedef T (*myfunctype)(T, T);
static myfunctype myhypot;
};

template<typename T>
typename temp<T>::myfunctype temp<T>::myhypot = 0;

// Can SFINAE work here??
template<>
temp<double>::myfunctype temp<double>::myhypot = hypot;

template<bool B, class T = void>
struct disable_if { typedef T type; };

template<class T>
struct disable_if<false, T> { };

// fallback hypot
template<typename T>
typename disable_if< temp<T>::myhypot , T>::type hypot(T x, T y) {
return sqrt(x * x + y * y); // ya ya, not accurate
}

int main() {
double x = 3.0, y = 5.0;
cout << hypot(x, y) << endl;
return 0;
}
 
F

Francesco S. Carta

Hey all,
I'm trying to provide fallbacks for a C99 function (hypot in cmath)
using "disable_if". Something like, "if hypot(double, double) is
not provided by cmath, use this instead"

What is wrong with simply overloading?

//-------
#include <iostream>

using namespace std;

namespace A {
void foo(int) {
cout << "foo(int)" << endl;
}
void foo(long) {
cout << "foo(long)" << endl;
}
}

namespace B {
template<class T> void foo(T) {
cout << "foo(T)" << endl;
}
}

using namespace A;
using namespace B;

int main() {
foo(42); // foo(int);
foo(78L); // foo(long);
foo(4.2); // foo(T);
foo('42'); // foo(int);
foo(char('42'));// foo(T);
}
//-------
 
J

Jonathan Lee

What is wrong with simply overloading?

It's already overloaded. The trouble is that some C++ compilers (GCC,
in particular) provide C99 functions that aren't (yet) C++ functions.
So <cmath> may or may not declare and define

hypot(double, double)
hypot(float, float)
hypot(long double, long double)

(Actually, probably hypotf, hypotl for the last two).

If they're already defined, I don't want to use mine. And, strictly
speaking, I can't. Right now I'm using an #ifdef block to manage
this.

I suppose, though, the more general question is whether or not
enable_if type constructs can be used to conditionally include
functions. I thought I was getting somewhere in this regard,
but then pfffffft

--Jonathan
 
I

Ian Collins

It's already overloaded. The trouble is that some C++ compilers (GCC,
in particular) provide C99 functions that aren't (yet) C++ functions.
So<cmath> may or may not declare and define

hypot(double, double)
hypot(float, float)
hypot(long double, long double)

(Actually, probably hypotf, hypotl for the last two).

If they're already defined, I don't want to use mine. And, strictly
speaking, I can't. Right now I'm using an #ifdef block to manage
this.

Can't you use a function template? If the real function declaration is
in scope, it will be used in preference.

For example:

#include <iostream>
//#include <math.h>

template <typename T> T hypot(T, T) { return 0; }

int main() {
std::cout << hypot( 2.0, 2.2 ) << std::endl;
}
I suppose, though, the more general question is whether or not
enable_if type constructs can be used to conditionally include
functions. I thought I was getting somewhere in this regard,
but then pfffffft

That's a different question. Are you sure you meant conditionally include?
 
F

Francesco S. Carta

It's already overloaded. The trouble is that some C++ compilers (GCC,
in particular) provide C99 functions that aren't (yet) C++ functions.
So<cmath> may or may not declare and define

hypot(double, double)
hypot(float, float)
hypot(long double, long double)

(Actually, probably hypotf, hypotl for the last two).

If they're already defined, I don't want to use mine. And, strictly
speaking, I can't. Right now I'm using an #ifdef block to manage
this.

I suppose, though, the more general question is whether or not
enable_if type constructs can be used to conditionally include
functions. I thought I was getting somewhere in this regard,
but then pfffffft

As an aside, I think it's impossible to do what you're trying to do.

Halting the compilation with an error, yes, that's a workaround with
templates that acts as a "compile assert", but continuing the
compilation after having found that some function isn't defined, not likely.

As the main point, I still cannot see why you couldn't simply overload.

You want specifically tailored overloads and not general templates, OK,
then specialize them.

If you add the following:

template<> void foo<long>(long) {
cout << "foo<long>()" << endl;
}

to namespace B in the code I posted before, the call to:

foo(42L);

will still print "foo(long)", but if you then comment out "void
foo(long)" from namespace A, the same call above will "fall back" to the
template you added.

What's is different WRT those C functions you want to overload?
 
J

Jonathan Lee

Can't you use a function template?  If the real function declaration is
in scope, it will be used in preference.

Actually, yeah. I think that'll work perfectly well. Stupid me.
That's a different question.  Are you sure you meant conditionally include?

Um... pretty sure. What I mean is: suppose you have code that depends
on a function f(). If there is already an f() with the same signature
(by time we reach the template) then continue using that function.
But if there is no f(), use the fall back function.

As a real world example, I have such a function to do wide
multiplication. i.e., it takes in two unsigned longs and outputs
the full result (high word and lo word). For the x86 architectures
I have versions of the function which use assembly language, but I
have fall back code in case the arch is different. Rather than use
ifdefs to select the appropriate code, I'd rather the fallback
kick in if a better version were not already defined.

--Jonathan
 
I

Ian Collins

Actually, yeah. I think that'll work perfectly well. Stupid me.


Um... pretty sure. What I mean is: suppose you have code that depends
on a function f(). If there is already an f() with the same signature
(by time we reach the template) then continue using that function.
But if there is no f(), use the fall back function.

I see. From my perspective, that isn't conditional inclusion!
Conditional inclusion would be used to exclude existing functions.
As a real world example, I have such a function to do wide
multiplication. i.e., it takes in two unsigned longs and outputs
the full result (high word and lo word). For the x86 architectures
I have versions of the function which use assembly language, but I
have fall back code in case the arch is different. Rather than use
ifdefs to select the appropriate code, I'd rather the fallback
kick in if a better version were not already defined.

The template approach would work. You could use specialisations for
specific hardware.
 
F

Francesco S. Carta

You and Ian are right. I was looking at it all backwards.

I know that feeling, don't worry: maybe you've discovered something new
about templates or about something else, and then that time has not been
spent in vain - that's my attitude when it happens to me, and it happens
to me ;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top