2015-09-29 17 views
11

Trong C++ 11, có cách nào để vô hiệu hóa chuyển đổi ngầm giữa typedefs, hoặc bạn phải làm điều gì đó khó chịu như bọc int của bạn trong một lớp và xác định và xóa các toán tử khác nhau?Vô hiệu hóa chuyển đổi ngầm giữa typedefs

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

Kiểu chữ không phải là loại thực, chúng chỉ là viết tắt hoặc bí danh cho loại thực. – Barmar

+0

Vì vậy, 'foo' và' bar' thực sự là cùng loại, và không có chuyển đổi nào liên quan. – Barmar

+0

Vâng, điều đó rõ ràng. Nhưng hiện đại C + + có một sự thay thế mà không tạo ra một loại mới mà không có một loạt các boilerplate? –

Trả lời

5

C++ chuẩn nói:

7.1.3 Các typedef specifier

Một tên tuyên bố với sự xác định typedef trở thành một typedef-name. Trong phạm vi tuyên bố của nó, một typedef tên là tương đương cú pháp với một từ khóa và tên loại liên kết với số nhận dạng trong cách được mô tả trong Điều 8. Một typedef-name là do đó một từ đồng nghĩa cho loại khác. Tên typedef không không giới thiệu loại mới theo cách khai báo lớp học (9.1) hoặc khai báo enum không

Nhưng ví dụ: class hoặc struct giới thiệu các loại mới. Trong ví dụ sau, uniqueUnused thực sự không có gì nhưng được sử dụng để tạo một loại khác nhau Value<int, 1> != Value<int, 2>. Vì vậy, có lẽ đây là thứ bạn đang tìm kiếm. Hãy nhớ rằng không có đảm bảo trình biên dịch được thoát khỏi cấu trúc bên ngoài! Việc bảo lãnh chỉ mã này mang đến cho bạn đó là kích thước giống như 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"); 

Nếu bạn muốn tạo một kiểu mới dựa trên một lớp học mà bạn có thể dễ dàng đi với ví dụ này (điều này không làm việc với các loại vô hướng từ bạn không thể kế thừa từ ints):

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

HelloWorld giải thích lý do bạn không thể làm việc gì. Bạn sẽ cần những gì thường được gọi là "mạnh" typedef để thực hiện những gì bạn muốn. An thực hiện ví dụ là 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) 
} 

Nếu chúng ta đã làm typedef int a;, sau đó mã sẽ là mơ hồ.

+0

Cũng là một cái hay. Có 'BOOST_STRONG_TYPEDEF' giới thiệu cũng là một trình bao bọc hay là nó miễn phí? – HelloWorld

+0

@HelloWorld "' BOOST_STRONG_TYPEDEF' là macro tạo lớp có tên "tên" bao bọc một thể hiện kiểu nguyên thủy của nó và cung cấp toán tử chuyển đổi thích hợp để làm cho kiểu mới có thể thay thế được cho lớp kết thúc tốt đẹp. " – Barry

+0

@HelloWorld Ngoài ra nó ** có ** để giới thiệu một wrapper, vì những lý do bạn đưa ra trong câu trả lời của bạn :) – Barry

-1

Nó không nghiêm ngặt loại kiểm tra, nhưng chuyển đổi bất hợp pháp có thể làm nhìn thấy bằng cách sử dụng gốc, hoặc Apps Hungary Notation (H. N.). Nếu bạn nghĩ H. N. có nghĩa là tên-kiểu-như-tiền tố, bạn sai (đó là Hệ thống H. N., và nó là, hm, phí đặt tên không cần thiết).

Sử dụng (Ứng dụng) H. N., tiền tố biến không đánh dấu loại (ví dụ: int), nhưng mục đích, ví dụ: truy cập, độ dài, giây vv Vì vậy, khi bạn thêm một truy cập vào một biến có chứa thời gian trôi qua, bạn viết cntSomethingCounter + secElapsedSinceLastSomething, và bạn có thể thấy rằng nó có mùi. Trình biên dịch không cảnh báo, nhưng nó chọc mắt bạn.

Đọc thêm: http://www.joelonsoftware.com/articles/Wrong.html

Các vấn đề liên quan