繁体   English   中英

使相同的C ++类型别名不兼容

[英]Making identical C++ type aliases incompatible

我使用std::vector<int>来获取两种不同的信息。 我想确保我不会意外地混合这两种用途。

简而言之,我想要像这段代码一样失败:

#include <vector>

using A = std::vector<int>;
using B = std::vector<int>;

void fa(const A&);
void fb(const B&);

void fun()
{
    A ax;
    B bx;

    fa(bx);
    fb(ax);
}

即使fa期望类型为A的参数,此代码也会编译。 显然, AB是相同的。

使这段代码正确编译的最简单方法是什么:

fa(ax);
fb(bx);

并使此代码失败:

fa(bx);
fb(ax);

当然,我可以将std::vector<int>包装在另一个类中,但是我需要重写它的接口。 或者,我可以从std::vector<int>继承,但经常不鼓励这样做。

简而言之,我需要两个不兼容的std::vector<int>

编辑

有人建议Strong typedef可以解决这个问题。 这只是部分正确。 如果我使用BOOST_STRONG_TYPEDEF(std::vector<int>, A) ,我需要添加一些讨厌的强制转换。 例如,而不是

A ax{1,3,5};

我需要用

A ax{std::vector<int>{1,3,5}};

而不是

for (auto x : ax) ...

我需要用

for (auto x : (std::vector<int>)ax) ...

我认为你想要的仍然是最好的:

struct A : public std::vector<int>{
  using vector::vector;
};
struct B : public std::vector<int>{
  using vector::vector;
};

它完全符合你的要求。 为了避免干净的陈述,没有理由想出一些丑陋的hackery。 我认为这种子类型不受欢迎的主要原因是相同的事物应该表现得像它们是相同的并且可以互换使用。 但这正是你想要压缩的东西,因此它的子类型恰好就是你想要的语句:它们具有相同的接口,但它们不应该被使用,因为它们不相同。

无论如何,这是一种原始的痴迷 int s确实代表了某些东西,而vector s是那个东西的集合,或者vector<int>代表了某种东西。

在这两种情况下,都应该通过将原语包装成更有意义的东西来解决。 例如:

class column
{
  int id;
  /*...*/
}; 
class row
{
  int id;
  /*...*/
};

std::vector<row>std::vector<column>不可互换。

当然,如果vector<int>是真正意味着其他东西的原语,那么同样的想法可以应用于vector<int>而不是int

或者,我可以从std :: vector继承,但这通常是不鼓励的。

IMO,这取决于具体情况。 一般来说可能是一个很好的解决方案

#include <vector>

class VectorA :
    public std::vector<int> {
 public:
  VectorA() = default;
  ~VectorA() = default;
  VectorA(const VectorA&) = default;
  VectorA(VectorA&&) = default;
  VectorA& operator=(const VectorA&) = default;
  VectorA& operator=(VectorA&&) = default;
};

class VectorB :
    public std::vector<int> {
 public:
  VectorB() = default;
  ~VectorB() = default;
  VectorB(const VectorB&) = default;
  VectorB(VectorB&&) = default;
  VectorB& operator=(const VectorB&) = default;
  VectorB& operator=(VectorB&&) = default;
};

您仍然可以使用VectorAVectorB作为法向量,但不能在它们之间切换。

void acceptA(const VectorA& v) {
  // do something
}

void acceptB(const VectorB& v) {
  // do something
}

template<typename T>
void acceptVector(const std::vector<T>& v) {
  // do something
}

int main(int argc, char *argv[]) {
  VectorA va;
  VectorB vb;

  acceptA(va);  // you can only pass VectorA
  acceptB(vb);  // same here for VectorB

  acceptVector(va);  // any vector
  acceptVector(vb);

  return 0;
}

这就是为什么你可以在C ++中进行面向对象编程以及重用库类型的基于对象的编程的部分原因。

制作A和B类,为您的域中的行为建模。 如果两个行为都是使用作为int的向量的字段实现的,那么这并不重要; 只要你不打破封装,对不同向量的所有操作都将在它们的类的范围内,并且不会发生混淆。

#include <vector>

class A {
    std::vector<int> cake_orders_;

public:
    void f() ; // can only do something to do with cake
};

class B {
    std::vector<int> meal_worm_lengths_;

public:
    void f() ; // can only do something to do with worms
};


void fun()
{
    A ax;
    B bx;

    a.f(); // has to be the right thing
    b.f();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM