禁用typedef之间的隐式转换

时间:2015-09-29 15:31:16

标签: c++ types typedef

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

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

4 个答案:

答案 0 :(得分:5)

C ++标准说:

  

7.1.3 typedef说明符

     

使用typedef说明符声明的名称将成为typedef-name。在其声明的范围内,typedef-name 在语法上等同于关键字,并命名与标识符相关联的类型   第8章中描述的方式.typedef-name是,因此是另一种类型的同义词。一个typedef-name可以   不按类声明(9.1)或枚举声明

的方式引入新类型

但是,例如classstruct引入新类型。在以下示例中,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;
};

答案 1 :(得分:5)

HelloWorld解释了为什么你所拥有的不起作用。你需要通常所说的“强大的”#34; 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;,那么代码就会模糊不清。

答案 2 :(得分:0)

我想做一些类似的事情,不仅在逻辑上保持不同的索引分开,而且还由编译器强制执行。我想出的解决方案基本上是用一个元素定义结构。在某些方面,它使用起来更痛苦,但它对我的情况非常有效,因为我经常不需要处理很多代码的索引的实际值,只需传递它即可。

typedef struct{uint16_t i;} ExpressionIndex;
typedef struct{uint16_t i;} StatementIndex;

现在,尝试做

ExpressionIndex foo() {
    StatementIndex i;
    return i;
}

产生错误 error: incompatible types when returning type ‘StatementIndex’ but ‘ExpressionIndex’ was expected

类型之间的转换有点痛苦,但这就是我改变的意图。

ExpressionIndex exp = (ExpressionIndex){stmt.i};

答案 3 :(得分:-1)

不是严格的类型检查,但非法转换可以使用原始或 Apps匈牙利表示法(H.N。)进行可见。如果您认为HN意味着名称类型为前缀,那么您就错了(它的系统HN ,以及它,嗯,不必要的命名开销)。< / p>

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

了解详情:http://www.joelonsoftware.com/articles/Wrong.html