问题 禁用typedef之间的隐式转换


在C ++ 11中,是否有一种干净的方法来禁用typedef之间的隐式转换,或者你是否需要做一些令人讨厌的事情,比如在类中包装int并定义和删除各种运算符?

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

10093
2017-09-29 15:31


起源

Typedef不是真正的类型,它们只是真实类型的shorthands或别名。 - Barmar
所以 foo 和 bar 实际上是同一类型,并没有涉及转换。 - Barmar
是的,这很清楚。但现代C ++是否有一个替代品可以创建一个没有一堆样板的新类型? - Andrew Wagner
@AndrewWagner号 - Baum mit Augen
@Barmar:我宁愿强调一件事和一件事之间的区别 名称 为了这件事。声明(包括typedef声明)介绍 名不是 类型。类型可以有许多名称。 - Kerrek SB


答案:


你好,世界 解释为什么你有什么不能工作。你需要通常被称为“强大”的东西 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;那么代码就会模糊不清。


5
2017-09-29 15:50



也是一个不错的。是否 BOOST_STRONG_TYPEDEF  还介绍一个包装或是免费的吗? - seb-mtl
@你好,世界 ”BOOST_STRONG_TYPEDEF 是一个生成名为“name”的类的宏,它包装了其基本类型的实例,并提供了适当的转换运算符,以使新类型可以替换它所包含的类型。“ - Barry
@HelloWorld也是 具有 介绍一个包装器,因为你在答案中给出的原因:) - Barry
谢谢。我只是在等待一些魔法,提升我不知道:) - seb-mtl


C ++标准说:

7.1.3 typedef说明符

使用typedef说明符声明的名称将成为typedef-name。在其声明的范围内,typedef-name是 语法上等同于关键字,并命名与标识符关联的类型 在   第8章中描述的方式.typedef-name是 因此是另一种类型的同义词。一个typedef-name可以   不要以类声明的方式引入新类型 (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");

如果你想基于一个类创建一个新类型,你可以简单地使用这个例子(这不适用于标量类型,因为你不能从int继承):

class Foo : public Bar // introduces a new type called Foo
{
    using Bar::Bar;
};

5
2017-09-29 15:43





这不是严格的类型检查,但可以进行非法转换 可见 通过使用原始,或 应用匈牙利表示法 (H.N.)。如果你认为H. N.意味着名字类型为前缀,那你就错了(就是这样 系统H. N.,它是,嗯,不必要的命名开销)。

使用(Apps)H.N。,变量前缀标记不是类型(例如, INT),但目的,例如,计数器,长度,秒等。因此,当您向变量添加计数器包含已用时间时,您可以编写 cntSomethingCounter + secElapsedSinceLastSomething,你可以看到它闻起来。编译器不会发出警报,但它会引起你的注意。

阅读更多: http://www.joelonsoftware.com/articles/Wrong.html


-1
2017-11-29 23:44