Toán tử lớp Templated + kiểu trả về quá tải


8

Tôi đang cố gắng xây dựng một lớp num templated. Lớp này cần phải có một thuộc tính công khai val, với kiểu T, là tham số templated duy nhất. Hơn nữa, nếu người ta cung cấp một giá trị, thuộc tính ( val) sẽ được khởi tạo với giá trị này. Để làm như vậy tôi đã thực hiện mã sau đây:

#include <iostream>

template<class T>
class Num {
public: 
    T val;

    Num():val(0) { std::cout<<"default constr used"<<std::endl; }
    Num(T value):val(value) {std::cout<<"constr (T value) used"<<std::endl; }
    ~Num() { std::cout<<"destructor used"<<std::endl; }

    template<typename U>
    Num operator+(const Num<U>& other) {
        return val+other.value;
    }
};

Hơn nữa, tôi đã tạo main()chức năng để kiểm tra chương trình, trông như thế này:

int main() {
    std::cout << Num<int>(1) + Num<double>(2.0);
    return 0;
}

Tuy nhiên, kết quả của chương trình là bây giờ 3. Trong khi đó tôi mong đợi nó là 3.0(loại double).


Nếu bạn muốn nhân đôi khi bạn có mã được viết ngay bây giờ, bạn sẽ cần phải lật các toán hạng đó. Num<int>(1) + Num<double>(2.0);giống như cách Num<int>(1).operator+(Num<double>(2.0))bạn đã khai báo là trả về giá trị của loại Num<int>.
scohe001

1
Điều này thậm chí sẽ không được biên dịch như nó là.
Ted Lyngmo

Tại sao điều đó sẽ cung cấp một lỗi biên dịch?
Juan Carlos Ramirez

3
@JuanCarlosRamirez Vì lớp không có biến thành viên có tên value.
Ted Lyngmo

Bạn nói đúng, không thấy điều đó.
Juan Carlos Ramirez

Câu trả lời:


10

Cho rằng bạn sẽ cần phải thay đổi loại trả lại.

Trong mã của bạn:

// vvv---- Means Num<T>
   Num operator+(const Num<U>& other) {
       return val + other.val;
   }

Thật vậy, bên trong một mẫu lớp, bạn có thể nhập tên của lớp mà không cần đối số mẫu và nó sẽ tương đương với việc viết Num<T>.

Hàm của bạn luôn trả về kiểu toán tử đầu tiên, bất kể loại bổ sung đó là gì.

Những gì bạn muốn là suy ra loại đó đến từ bổ sung:

auto operator+(const Num<U>& other) -> Num<decltype(val + other.val)> {
    return val + other.val;
}

Theo cách đó, nó luôn là kiểu trả về đúng theo quy tắc toán tử C ++.


2
trong c ++ 14 trở lên, bạn không cần-> Num<decltype(val + other.val)>
BЈовић 10/12/19

@ BЈовић, anh ta cần nó. Nếu không, kiểu trả về sẽ là decltype(val + other.val), và không Num<decltype(val + other.val)>.
Evg

@ BЈовић Trong C ++ 17 Tôi sẽ sử dụng khấu trừ kiểu trả về và khấu trừ đối số mẫu lớp để trả vềNum{val + other.val}
Guillaume Racicot

9

operator+nên đối xứng với các đối số của nó. Tốt hơn là nên thực hiện như một hàm miễn phí thay vì hàm thành viên để làm cho tính đối xứng này rõ ràng.

Ví dụ: (sử dụng khấu trừ kiểu trả về C ++ 14):

template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
    using R = decltype(std::declval<T>() + std::declval<U>());
    return Num<R>{x.val + y.val};
}

std::declval<T>()có tính tổng quát , nếu Tvà / hoặc Ukhông thể xây dựng mặc định. Nếu các loại được giới hạn trong các loại tích hợp, như intdouble, nó có thể được thay thế bằng T{}hoặc T():

using R = decltype(T{} + U{});

Với việc khấu trừ đối số mẫu lớp trong C ++ 17, nó có thể được đơn giản hóa hơn nữa:

template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
    return Num{x.val + y.val};
}

Wow tôi không biết rằng bạn có thể auto đi một loại trở lại. Cái này hay đấy.
scohe001

@ scohe001, đó là tính năng C ++ 14.
Evg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.