Trong một nỗ lực để viết một loại wrapper
cho một loại T
, tôi gặp phải một vấn đề khá khó chịu: Tôi muốn xác định một số nhà khai thác nhị phân (chẳng hạn như +
) mà chuyển tiếp bất kỳ hoạt động trên wrapper
đến loại cơ bản, nhưng tôi cần những nhà khai thác chấp nhận bất kỳ sự kết hợp tiềm năng có liên quan đến wrapper
:đệ quy Infinite với `enable_if`
wrapper() + wrapper()
wrapper() + T()
T() + wrapper()
cách tiếp cận ngây thơ liên quan đến văn bản tất cả các quá tải tiềm năng trực tiếp.
Nhưng tôi không thích viết mã trùng lặp và muốn thử thách hơn một chút, vì vậy tôi đã chọn triển khai mã đó bằng cách sử dụng mẫu rất chung chung và hạn chế các loại tiềm năng có số enable_if
.
Nỗ lực của tôi được hiển thị ở cuối câu hỏi (xin lỗi, điều này là tối thiểu như tôi có thể nghĩ đến). Vấn đề là nó sẽ chạy vào một lỗi đệ quy vô hạn:
- Để đánh giá
test() + test()
, biên dịch xem xét tất cả tình trạng quá tải tiềm năng. - Toán tử được xác định ở đây thực tế là tình trạng quá tải tiềm ẩn, do đó, nó cố gắng tạo kiểu trả về.
- Kiểu trả về có
enable_if
khoản, mà là vụ để ngăn chặn nó từ một tình trạng quá tải hiệu lực, nhưng trình biên dịch chỉ cần bỏ qua điều đó và cố gắng tính toándecltype
đầu tiên, đòi hỏi ... - ... một instantiation của
operator+(test, test)
.
Và chúng tôi quay lại nơi chúng tôi bắt đầu. GCC là tốt đẹp, đủ để nhổ một lỗi; Clang chỉ segfaults.
Giải pháp nào là tốt, sạch cho việc này? (Hãy nhớ rằng cũng có những nhà khai thác khác mà cần phải làm theo cùng một khuôn mẫu.)
template<class T>
struct wrapper { T t; };
// Checks if the type is instantiated from the wrapper
template<class> struct is_wrapper : false_type {};
template<class T> struct is_wrapper<wrapper<T> > : true_type {};
// Returns the underlying object
template<class T> const T& base(const T& t) { return t; }
template<class T> const T& base(const wrapper<T>& w) { return w.t; }
// Operator
template<class W, class X>
typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value,
decltype(base(declval<W>()) + base(declval<X>()))
>::type operator+(const W& i, const X& j);
// Test case
struct test {};
int main() {
test() + test();
return 0;
}
Dưới đây là giải pháp khá vụng về mà tôi không muốn sử dụng, trừ khi tôi phải:
// Force the evaluation to occur as a 2-step process
template<class W, class X, class = void>
struct plus_ret;
template<class W, class X>
struct plus_ret<W, X, typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value>::type> {
typedef decltype(base(declval<W>()) + base(declval<X>())) type;
};
// Operator
template<class W, class X>
typename plus_ret<W, X>::type operator+(const W& i, const X& j);
tại một số điểm việc chữa bệnh tệ hơn bệnh. Chỉ cần cắn đạn và viết 3 quá tải. – TemplateRex
Sẽ là một điều đáng tiếc nếu đó là trường hợp. Oh well. – Rufflewind
xem câu trả lời của tôi cho 2 phương pháp tiếp cận – TemplateRex