In C++11, is there a clean way to disable implicit conversion between typedefs, or do you have to do something nasty like wrap your int in a class and define and delete various operators?
typedef int Foo;
typedef int Bar;
Foo foo(1);
Bar bar(2);
bar = foo; // Implicit conversion!
You can avoid implicit type casting by instead using explicit type casting or by adding generated columns.
An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.
Implicit Type Conversion Also known as 'automatic type conversion'. Done by the compiler on its own, without any external trigger from the user. Generally takes place when in an expression more than one data type is present. In such condition type conversion (type promotion) takes place to avoid lose of data.
HelloWorld explains why what you have cannot work. You'll need what's typically called a "strong" typedef
to do what you want. An example implementation is BOOST_STRONG_TYPEDEF
:
#include <boost/serialization/strong_typedef.hpp>
BOOST_STRONG_TYPEDEF(int, a)
void f(int x); // (1) function to handle simple integers
void f(a x); // (2) special function to handle integers of type a
int main(){
int x = 1;
a y;
y = x; // other operations permitted as a is converted as necessary
f(x); // chooses (1)
f(y); // chooses (2)
}
If we had done typedef int a;
, then the code would be ambiguous.
The C++ standard says:
7.1.3 The typedef specifier
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does
But e.g. class
or struct
introduce new types. In the following example uniqueUnused
does actually nothing but is used to create a different type Value<int, 1> != Value<int, 2>
. So maybe this is something you are looking for. Keep in mind there is no guarantee the compiler gets rid of the outer structure! The only guarantee this code gives you it's the same size as int
template<typename T, int uniqueUnused>
struct Value
{
Value() : _val({}) {}
Value(T val) : _val(val) { }
T _val;
operator T&() { return _val; }
// evaluate if you with or without refs for assignments
operator T() { return _val; }
};
using Foo = Value<int, 1>;
using Bar = Value<int, 2>;
static_assert(sizeof(Foo) == sizeof(int), "int must be of same size");
static_assert(sizeof(Bar) == sizeof(int), "int must be of same size");
If you want to create a new type based on a class you can simply go with this example (this doesn't work with scalar types since you can't inherit from ints):
class Foo : public Bar // introduces a new type called Foo
{
using Bar::Bar;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With