2013-07-19 39 views
24

Hãy xem xét một lớp int Wrapper đơn giản với phép nhân quá tải operator*=operator*. Đối với toán tử "kiểu cũ" quá tải, người ta có thể xác định operator* theo điều khoản của operator*= và thậm chí có cả thư viện như Boost.Operators và hiện thân của nó df.operators bởi @DanielFrey làm giảm bản mẫu cho bạn.Hướng dẫn thực hiện quá trình vận hành quá tải?

Tuy nhiên, để tính toán thời gian biên dịch bằng C++ 11 constexpr mới, sự tiện lợi này biến mất. A constexpr operator* không thể gọi operator*= vì sau này sửa đổi đối số bên trái (ẩn) của nó. Hơn nữa, có no overloading on constexpr, vì vậy, hãy thêm constexpr operator* vào kết quả hiện tại của sự thiếu mơ hồ về độ phân giải quá tải.

cách tiếp cận hiện tại của tôi là:

#include <iostream> 

struct Wrap 
{ 
    int value;  

    Wrap& operator*=(Wrap const& rhs) 
    { value *= rhs.value; return *this; } 

    // need to comment this function because of overloading ambiguity with the constexpr version 
    // friend Wrap operator*(Wrap const& lhs, Wrap const& rhs) 
    // { return Wrap { lhs } *= rhs; }  

    friend constexpr Wrap operator*(Wrap const& lhs, Wrap const& rhs) 
    { return { lhs.value * rhs.value }; } 
}; 

constexpr Wrap factorial(int n) 
{ 
    return n? factorial(n - 1) * Wrap { n } : Wrap { 1 };  
} 

// want to be able to statically initialize these arrays 
struct Hold 
{ 
    static constexpr Wrap Int[] = { factorial(0), factorial(1), factorial(2), factorial(3) }; 
}; 

int main() 
{ 
    std::cout << Hold::Int[3].value << "\n"; // 6 
    auto w = Wrap { 2 }; 
    w *= Wrap { 3 }; 
    std::cout << w.value << "\n"; // 6 
} 

Live output here. vấn đề của tôi với điều này là:

  • trùng lặp logic nhân trong cả hai operator*=operator*, thay vì operator* được biểu diễn dưới dạng operator*=
  • do đó, Boost.Operators không còn hoạt động để giảm soạn sẵn để viết nhiều toán tử số học khác

Câu hỏi: là này cách đề nghị C++ 11 có cả một thời gian chạy operator*= và trộn thời gian chạy/thời gian biên dịch 01.237.? C++ 14 có thay đổi bất kỳ thứ gì ở đây không, ví dụ: giảm trùng lặp logic?

CẬP NHẬT: Câu trả lời bởi @AndyProwl được chấp nhận như là thành ngữ nhưng theo đề nghị của @DyP, trong C++ 11 một thể giảm sự trùng lặp logic tại các chi phí của một bài tập thêm phong cách và phản trực giác

// define operator*= in terms of operator* 
    Wrap& operator*=(Wrap const& rhs) 
    { *this = *this * rhs; return *this; } 
+0

Việc sử dụng của bạn cho quá tải 'thường xuyên' là gì nếu nó có thể là 'constexpr'? IIRC 'constexpr' sẽ giáng xuống một cách duyên dáng thành _runtime execution_ trong ngữ cảnh không phải 'constexpr'. – sehe

+1

@ bạn không thể có toán tử 'constexpr * =', và vì vậy 'toán tử constexpr *' không thể gọi hàm này, và thay vào đó cần lặp lại logic của các trường trích xuất v.v. – TemplateRex

+1

Ah, tôi bắt đầu thấy câu hỏi thực của bạn. Đó là *** không *** về việc không có quá tải 'constexpr' (bạn không cần chúng!) Mà đúng hơn là không thể chia sẻ mã vì '* =' không thể là 'constexpr'.Điều tốt tôi đã + 1 trên niềm tin tốt :) – sehe

Trả lời

17

tôi không thể tìm thấy một giải pháp thành ngữ cho C++ 11 (mặc dù là một cách giải quyết, DyP's suggestion dường như chấp nhận được đối với tôi).

Trong tuy nhiên C++ 14, nơi constexpr does not imply const (xem Phụ lục C.3.1 của C++ 14 Chuẩn Draft n3690), bạn có thể chỉ đơn giản là xác định cả operator *=operator * như constexpr, và xác định sau này trong điều khoản của cựu , như thường lệ:

struct Wrap 
{ 
    int value;  

    constexpr Wrap& operator *= (Wrap const& rhs) 
    { value *= rhs.value; return *this; } 

    friend constexpr Wrap operator * (Wrap const& lhs, Wrap const& rhs) 
    { return Wrap(lhs) *= rhs; }  
}; 

đây là một live example, nơi mà các chương trình trên đã được biên soạn với -std=c++1y trên Clang - không may, GCC dường như không thực hiện quy định này được nêu ra.

+0

Bạn nghĩ gì về đề xuất của DyP về việc đảo ngược sự phụ thuộc với chi phí của một nhiệm vụ? – TemplateRex

+5

@TemplateRex: Vâng, tôi đã tự nghĩ về điều đó, nhưng tôi đã không đăng nó như một giải pháp vì nó sẽ đi ngược lại việc thực hành tiêu chuẩn. Hoàn nguyên hướng dẫn khi một thay đổi cho phép đã sẵn sàng cho C++ 14 sẽ là IMO không phù hợp. Tuy nhiên, như một giải pháp C++ 11, nó phải được chấp nhận. Tôi thành thật không nghĩ rằng hiệu suất sẽ là một vấn đề ở đây - Tôi không có chuyên gia biên dịch, nhưng tôi hy vọng trình tối ưu hóa sẽ thực hiện nội tuyến nặng cho các chức năng đơn giản như vậy. Ngoài ra, tôi cố gắng tránh tối ưu hóa sớm và tránh từ chối thiết kế chỉ vì các giả định về hiệu suất. –

+0

'constexpr' không còn ngụ ý' const' sang một bên, tôi bối rối ** tại sao ** nó hoạt động: 'operator * =' là cả hai biến và đa biến 'this', nhưng nó đang được gọi trong thời gian biên dịch. Cả hai hạn chế đó * cũng có được xóa trong C++ 14 không? Bạn có báo giá làm việc trên giấy không? – TemplateRex

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