Limiting function input only to __int64 but not int...

A

A

Is there a way (except overloading) to limit function input to accept
__int64 but to get a compiler (preferable) or runtime (less preferable)
error if it is called with int?

for example:

void myfunction(__int64 param) // Accepts only __int64 as input and no
smaller
{
}

myfunction((__int64)1); // Call OK
myfunction((int)1); // Call fails or better - compiler reports error
 
I

Ian Collins

Is there a way (except overloading) to limit function input to accept
__int64 but to get a compiler (preferable) or runtime (less preferable)
error if it is called with int?

for example:

void myfunction(__int64 param) // Accepts only __int64 as input and no
smaller
{
}

myfunction((__int64)1); // Call OK
myfunction((int)1); // Call fails or better - compiler reports error

You can use a function template to force a link error:

#include <stdint.h>

template <typename T> void f( T n );

template <> void f( int64_t n ) // Specialise for acceptable types
{
}

Or give the function template a body to force a compiler warning:

template <typename T> void f( T n )
{
T tmp = n/0;
}
 
M

Marc

A" said:
Is there a way (except overloading) to limit function input to accept
__int64 but to get a compiler (preferable) or runtime (less preferable)
error if it is called with int?

Assuming that __int64 is not the same type as int.

with overloading (what's wrong with overloading?):
void f(long){}
void f(int)=delete;

with sfinae:
template<class T,class=typename std::enable_if<std::is_same<T,long>::value>::type> void f(T){}
 
A

A

Thank you for your answers so far. I was hoping though for something without
templates. I did found though BOOST_STRONG_TYPEDEF which pretty much does
this.
 
G

Goran

Is there a way (except overloading) to limit function input to accept
__int64 but to get a compiler (preferable) or runtime (less preferable)
error if it is called with int?

Out of curiosity... Why? int "is an" __int64 any way you look at this.
Why would it matter?

Goran.
 
M

Marcel Müller

Is there a way (except overloading) to limit function input to accept
__int64 but to get a compiler (preferable) or runtime (less preferable)
error if it is called with int?
for example:

void myfunction(__int64 param) // Accepts only __int64 as input and no
smaller
void myfunction(const __int64& param);


Marcel
 
I

Ian Collins

void myfunction(const __int64& param);

Won't the normal promotion rules still apply?

myfunction( 2 );

Compiles happily as does

int n = 0;
myfunction( n );
 
I

Ian Collins

Won't the normal promotion rules still apply?

myfunction( 2 );

Compiles happily as does

int n = 0;
myfunction( n );

Hit send too soon, I was going to add that

void myfunction( int64_t& param );

was probably what you intended to type.
 
J

Juha Nieminen

Ian Collins said:
Or give the function template a body to force a compiler warning:

template <typename T> void f( T n )
{
T tmp = n/0;
}

I don't think that's a very good idea.
 
A

A

Goran said:
Out of curiosity... Why? int "is an" __int64 any way you look at this.
Why would it matter?

because function requires explicitly __int64 because ID's are 64-bit,
providing 32-bit int would ruin ID's that go over the 32-bit boundary. This
may happen when I do text-to-int conversions using StrToInt and forget to
put StrToInt64 instead.

In Borlangearcadero C++ Builder 2010 which I use, these functions output int
and __int64 so compiler SHOULD be able to check these but unfortunately it
doesn't - even if I enable W8102 Implicit conversion of '%s' to '%s' (C++)
but it doesn't do what it is supposed to. I tried casting to wrong type but
the warning is still not triggered.
 
R

Richard Damon

Why not use the usual trick of imbedding the handle in a structure?

struct MyHandle(__int64 h;};

And use a MyHandle as the parameter or return value?

Alternatively, explicitly declare forms for those functions using int,
short, etc., and then never define them - that way the link will fail.
Better yet, if your compiler supports the new standard, use the
"=delete" form:

void f(__int64); //supply actual definition
void f(int)=delete; //can't be called

Of course that's ugly because of the number of definitions you need to
supply to cover all of the usual conversions.

Actually, once you define one disallowed form, the rest become
ambiguous. For example, calling with a "short" neither short->int or
short->__int64 has a preference, so I believe it should give an error. I
don't think the =delete removes that version from overload resolution,
but I haven't looked at it in detail yet.
 
A

A

Robert Wessel said:
void f(__int64); //supply actual definition
void f(int)=delete; //can't be called

I actually like this solution but the compiler doesn't support it. I guess
I'll be looking for alternate solutions.
 
R

Richard Damon

I actually like this solution but the compiler doesn't support it. I guess
I'll be looking for alternate solutions.

if it doesn't support the =delete syntax, declaring (but not defining)
void f(unsigned char); (choose an integer type that you are actually
unlikely to mistakenly use) will make a call of f(1) ambiguous and thus
an error. You want to make the undefined type an unlikely mistake as if
you use it by mistake, you are just going to get a link error, and you
will have to search to find where it is actually called.
 
A

Arne Mertz

Maybe it supports #pragma error?
Then you can write

#pragma error is not very portable, e.g. MSVC does not
sopport it, instead, it issues a warning about the
unsupported pragma and happily continues compiling,
i.e. f(int) may be called.

overloading f(int) and f(__int64) imo is not a good idea,
because once you port the whole thing to a 64 bit machine
int and __int64 become the same and you get either a
redefinition error (if you actually defined f(int)), or
the whole "error detection via link error or ambiguity"
magically dissapears if you only declared f(int), as it
is just another declaration of f(__int64).
In your case the latter behavior may be ok, if the
problem is only about disambiguating 32 bit int and __in64
in 32 bit systems. But maybe StrToInt outputs __int32
even on 64 bit systems or something similar happens so you
want to keep up the 32 bit integer detection even on 64 bit
systems.

To make things short(er), I would use overloading, but not
with any specific integer type but with a template:
given f(__int64) as the function to be called only for
64bit types, you have several variants

Variant a)
template <typename T>
void f(T) = delete; //overload resolution calls this for
any T that is not the same as __int64

Variant b), C++0x without deleted functions
template <typename T>
void f(T)
{ static_assert(false, "call f only with __int64!"); }

Variant c), C++0x, less restrictive
#include <type_traits>
template <typename T>
f(T t) -> decltype(f(__int64))
{
// assert T is "sufficiently close to" __int64
static_assert(std::is_integral<T>::value
&& std::is_convertible<T, __int64>::value
&& sizeof(T) >= sizeof(__int64));

return f(__int64(t));
}

If your compiler lacks support for static_assert, you
could use either std::enable_if or the STATIC_ASSERT
macro from the loki library. If your standard library
has no <type_traits>, boost provides similar utilities.

HTH Arne
 

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

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top