2016-04-27 13 views
7

Hãy xem xét các loại sau đây:quá tải với typedef cho một lỗi

#include <iostream> 

typedef unsigned long long  usize_t; 
typedef unsigned __int16  uword_t; 
typedef uword_t     clockval_t;  // time without seconds in format HHMM 

std::string toString(clockval_t nClock) 
{ 
    return std::to_string((usize_t)nClock/100) + ":" + std::to_string((usize_t)nClock % 100); 
} 

std::string toString(uword_t nValue) 
{ 
    return std::to_string((usize_t)nValue); 
} 

void test(void) 
{ 
    uword_t val = 1; 
    clockval_t time = 1023; // 10:23 

    std::cout << "Value: " << toString(val); 
    std::cout << "time: " << toString(time); 
} 

Bây giờ khi tôi cố gắng biên dịch này, tôi nhận được một lỗi từ trình biên dịch nói với tôi rằng std::string toString(clockval_t) đã có một cơ thể. Tôi hiểu tại sao điều này xảy ra tất nhiên, bởi vì typedef chỉ là một bí danh cho uword_t.

AFAIK các giải pháp chỉ là để cung cấp một phương pháp riêng biệt:

std::string toClockString(clockval_t); 

hoặc làm cho nó một đối tượng:

class clockval ... 

là đúng này hoặc là có một số cách khác để làm cho trình biên dịch chọn quá tải chính xác?

+0

Ah, niềm vui của hệ thống loại C! – Sean

+2

Vâng, IMO hơi yếu, bởi vì toàn bộ điểm của typedef là tạo các kiểu mới, do đó trình biên dịch có thể phân biệt chúng một cách chính xác để làm cho nó phù hợp. Tôi đoán có một số vấn đề tương thích ngược có liên quan mặc dù. – Devolus

Trả lời

2

Thậm chí nếu có một cách để làm cho trình biên dịch chọn phiên bản chính xác, bạn có nhận ra nó sẽ dễ bị lỗi như thế nào không? May mắn thay, không có cách nào như vậy vì typedef tạo bí danh và không có gì khác.

Tôi đề nghị bạn chuyển nó thành lớp. Nếu bạn cung cấp nhà xây dựng và nhà điều hành chuyển đổi phù hợp thì bạn thậm chí không cần phải thay đổi các phần mã sử dụng clockval_t:

class clockval_t { 
public: 
    clockval_t(uword_t aValue) : value(aValue) {} 
    operator uword_t() const { return value; } 

private: 
    uword_t value; 
}; 

... 

clockval_t time = 1023; // works fine 
std::cout << time << std::endl; // works fine 
std::cout << (time/10) << std::endl; // works fine 
+0

CẢM ƠN! Đây chắc chắn là câu trả lời tốt nhất.:) Tôi đã kiểm tra mã máy để đảm bảo rằng không có chi phí không cần thiết như trái ngược với một từ đơn giản (mà có thể là mối quan tâm chính của tôi đối với một đối tượng) và điều này hoạt động giống như 'word' trong khi có lợi ích của loại . :) – Devolus

+0

Điều này có một nhược điểm là bạn đang mất tất cả các phép tính số học trên clockval_t. Bạn sẽ cần xác định lại mọi toán tử trong lớp (nếu cần). –

0

Ý nghĩa của typedef được định nghĩa trong tiêu chuẩn như (7.1.3 Các typedef specifier):

Trong phạm vi của việc kê khai, một typedef-name là cú pháp tương đương với một từ khóa và tên loại liên kết với số nhận dạng (...). Do đó, tên typedef là một từ đồng nghĩa cho một loại khác. Một typedef-tên không không giới thiệu một loại mới (...).

Do đó, hai hàm thực sự mơ hồ về loại tham số đầu vào. Bạn cần phải phân biệt loại (ví dụ: bằng cách sử dụng loại khác nhau, ví dụ: một lớp hoặc enum) hoặc có thể thêm tham số thứ hai (có thể có giá trị mặc định) cho biết loại chính xác nào đang được chuyển.

Liên kết đến câu trả lời gốc : https://softwareengineering.stackexchange.com/questions/254473/in-which-stage-of-compilation-is-typedef-resolved-by-the-compiler

+0

Tôi thích câu trả lời này vì trích dẫn, nhưng tôi đồng ý với câu trả lời được chấp nhận, thêm một tham số giả không phải là một ý tưởng hay, và về cơ bản rất giống với việc tạo một tên hàm cụ thể. – Devolus

1

Điều này đúng hay có cách nào khác để làm cho trình biên dịch chọn quá tải chính xác?

Có chính xác, bạn không thể quá tải trên typedef vì nó chỉ đơn giản là bí danh. Khi bạn đề xuất đúng, hãy đổi tên hàm hoặc tạo một loại mới với class. Việc thêm thông số giả chỉ đơn giản là thay đổi chữ ký chức năng thường là ý tưởng tồi, đổi tên rõ ràng hơn.

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