[英]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
的參數,此代碼也會編譯。 顯然, A
和B
是相同的。
使這段代碼正確編譯的最簡單方法是什么:
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;
};
您仍然可以使用VectorA
和VectorB
作為法向量,但不能在它們之間切換。
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.