Отключить неявное преобразование между typedefs
В С++ 11 есть ли чистый способ отключить неявное преобразование между typedefs, или вам нужно сделать что-то неприятное, как обернуть int в класс и определить и удалить различные операторы?
typedef int Foo;
typedef int Bar;
Foo foo(1);
Bar bar(2);
bar = foo; // Implicit conversion!
Ответы
Ответ 1
В стандарте С++ говорится:
7.1.3 Спецификатор typedef
Имя, объявленное с помощью спецификатора typedef, становится typedef-name. В пределах своей декларации имя typedef синтаксически эквивалентно ключевому слову и называет тип, связанный с идентификатором в способ, описанный в разделе 8. typedef-name , таким образом, является синонимом другого типа. Имя typedef не вводить новый тип так, как декларация класса (9.1) или декларация перечисления делает
Но, например, class
или struct
вводят новые типы. В следующем примере uniqueUnused
фактически ничего не используется, но используется для создания другого типа Value<int, 1> != Value<int, 2>
. Так что, возможно, это то, что вы ищете. Имейте в виду, что нет гарантии, что компилятор избавится от внешней структуры! Единственная гарантия этого кода дает вам тот же размер, что и 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");
Если вы хотите создать новый тип на основе класса, вы можете просто пойти с этим примером (это не работает со скалярными типами, поскольку вы не можете наследовать от ints):
class Foo : public Bar // introduces a new type called Foo
{
using Bar::Bar;
};
Ответ 2
HelloWorld объясняет, почему то, что у вас есть, не может работать. Вам понадобится то, что обычно называют "сильным" typedef
, чтобы делать то, что вы хотите. Пример реализации: 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)
}
Если бы мы сделали typedef int a;
, тогда код был бы неоднозначным.
Ответ 3
Это не строгая проверка типов, но незаконные конверсии могут сделать видимыми, используя оригинал или венгерскую ноту Apps (H.N.). Если вы считаете, что H. N. означает имя-тип-префикс, вы ошибаетесь (это System H. N., и это, hm, ненужные накладные расходы).
Используя (Apps) H. N., префикс переменной указывает не тип (например, int), а цель, например. счетчик, длина, секунды и т.д. Итак, когда вы добавляете счетчик в переменную, истекшее время, вы пишете cntSomethingCounter + secElapsedSinceLastSomething
, и вы можете видеть, что он пахнет. Компилятор не предупреждает, но он ткнул ваши глаза.
Подробнее: http://www.joelonsoftware.com/articles/Wrong.html