Подтвердить что ты не робот

Отключить неявное преобразование между typedefs

В С++ 11 есть ли чистый способ отключить неявное преобразование между typedefs, или вам нужно сделать что-то неприятное, как обернуть int в класс и определить и удалить различные операторы?

typedef int Foo;
typedef int Bar;
Foo foo(1);
Bar bar(2);
bar = foo; // Implicit conversion!
4b9b3361

Ответ 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