Reputation: 383
Currently I have a problem with code portability from 64 (back) to 32 bit. The problem is, that a method of a class is overloaded for 64 bit platforms that conflicts with another overload on 32 bit platforms.
The two methods look like this:
void myfunc(unsigned o);
void myfunc(size_t o);
On 32 bit architectures, they look identical to the compiler and throw some error.
So, the question is, is it possible to do something like this:
void myfunc(unsigned o);
#if typeid(unsigned) != typeid(size_t)
void myfunc(size_t o);
#endif
My current solution looks like this:
void myfunc(unsigned o);
#if __WORDSIZE == 64
void myfunc(size_t o);
#endif
But there is some bad feeling left, that WORDSIZE is not the best fit, because it does not necessarily mean, that the types are not the same.
OK, here is the problematic place line 705 and 706, that produce an error when compiling on 32-bit ARM.
Upvotes: 1
Views: 1093
Reputation: 18228
You can use std::enable_if
for that:
#include <type_traits>
struct S {
void advance(unsigned o);
std::enable_if<!std::is_same<unsigned, std::size_t>::value>::type
advance(std::size_t o) { advance(static_cast<unsigned>(o)); }
};
Though, as others have already pointed out, I would ditch the unsigned
variant and keep only the std::size_t
variant.
Upvotes: 0
Reputation:
If the underlying C standard library supports the "Floating-point extensions part 1" (ISO/IEC TS 18661-1:2014), then you have preprocessor macros available that can be used to identify the sizes of types:
#include<climits>
#include<cstdint>
void myfunc(unsigned o);
#if UINT_WIDTH != SIZE_WIDTH
void myfunc(size_t o);
#endif
This is supported e.g. by glibc. Beware that the test always fails if the macros are not defined, i.e. if the specification is not implemented, so you should probably check for that as well, i.e.
#if UINT_WIDTH != SIZE_WIDTH || !defined(UINT_WIDTH) || !defined(SIZE_WIDTH)
Without such implementation-defined macros, the preprocessor cannot be used to achieve what you want, as it doesn't actually know about C or C++ types.
Any solution at the C++ compilation level will require you to at least somewhat modify the function declarations.
I do not consider this solution particularly clean, but your current solution isn't either. Really, if as I suspect, the goal is to avoid certain implicit conversions, the method should be a template with a static_assert
limiting the type as appropriate.
Edit:
The code above works as is with a current glibc and gcc, but I am not sure whether technically this is correct behavior. This is a technical specification extending C11, not C++. I don't know how or whether C++ incorporates these or if they would be considered implementation-defined extensions.
Also according to the specification the macros should only be defined if you
#define __STDC_WANT_IEC_60559_BFP_EXT__
before the first #include<stdint.h>
or #include<limits.h>
. When compiling in C mode GCC with glibc does actually require this.
Whether the specification is implemented can be checked by comparing the macro __STDC_IEC_60559_BFP__
against 201ymmL
. However GCC with glibc does not seem to set this macro and the documentation notes that support of the specification is only partial.
Probably you should at least make sure that UINT_WIDTH
and SIZE_WIDTH
are set before trusting the comparison made above. If they are not, e.g. because the specification is not supported is will evaluate always to 0 != 0
, i.e. false
.
Upvotes: 3
Reputation: 614
This might be an option using templates:
#include <iostream>
class A {
public:
template<typename T>
std::enable_if_t<std::is_same<T, int>::value ||
std::is_same<T, unsigned>::value ||
std::is_same<T, std::size_t>::value >
advance(T o) {
std::cout << "s" << std::endl;
A::advance<unsigned>(static_cast<unsigned>(o));
}
};
template<>
void A::advance(int o) = delete;
template<>
void A::advance(unsigned o) {
std::cout << "u" << std::endl;
}
int main()
{
A a;
unsigned x;
std::size_t y;
int z;
char p;
a.advance(x);
a.advance(y);
//a.advance(z);
//a.advance(p);
return 0;
}
Upvotes: 1