So, I know you can alias types with the following:
typedef int *intPtr
But the C++ compiler can\'t differentiate between them:
typedef int
One way to create a type that acts like a new integral type is to use a based enum
. But beware: an enum
is not formally an integral type. It's only its base type that is an integral type.
Also, a heads-up: I've never found this useful enough to do it.
That said, it can go like this:
#include <type_traits> // std::underlying_type
#include <utility> // std::enable_if
//----------------------------------------- Machinery:
namespace cppx {
using std::enable_if_t;
using std::underlying_type_t;
namespace impl {
inline constexpr auto is_a_typed_integer( ... ) -> bool { return false; }
} // namespace impl
template< class Type >
inline constexpr auto is_typed_integer()
-> bool
{
using impl::is_a_typed_integer;
return is_a_typed_integer( Type() );
}
namespace enum_arithmetic {
template< class Enum
, class Enabled_ = enable_if_t< is_typed_integer<Enum>(), void >
>
inline auto operator+( Enum const a, Enum const b )
-> Enum
{
using Integral = underlying_type_t<Enum>;
return Enum( Integral( a ) + Integral( b ) );
}
}
} // namespace cppx
//----------------------------------------- Usage:
namespace my {
using cppx::enum_arithmetic::operator+; // Makes it accessible via ADL.
enum class Foo: int {};
inline constexpr auto is_a_typed_integer( Foo ) -> bool { return true; }
enum class Bar: int {};
} // namespace my
//----------------------------------------- Test:
#include <iostream>
using namespace std;
auto main() -> int
{
auto x = my::Foo( 5 );
auto y = my::Bar( 7 );
(void) y;
#ifdef TRY_CONVERSION
int z = x + y; //! No implicit conversion.
(void) z;
#endif
cout << boolalpha;
cout << "Foo -> " << cppx::is_typed_integer<my::Foo>() << endl; // true
cout << "Bar -> " << cppx::is_typed_integer<my::Bar>() << endl; // false
auto x2 = x + x;
cout << int( x2 ) << endl;
#ifdef TRY_BAR
auto y2 = y + y; //! Not an arithmetic type.
(void) y2;
#endif
}
A typedef
or using
statement will not introduce a new type.
To get a new type you need to define one:
struct foo { int x; };
struct bar { int x; };
int main()
{
//typedef int foo;
//typedef int bar;
foo x{5};
bar y{7};
int z = x + y; // now doesn't compile, wants an operator+() defined
return 0;
}
In the above example we take advantage of aggregate initialization to allow for the use of the structs
in this way.