2014-10-17 23 views
10

Giả sử tôi có một lớp học với các chữ ký sau:Làm cách nào để enable_if một lớp với đối số mẫu có định dạng variadic?

template <typename T, typename... Args> 
class A; 

Nhưng cách này cư xử lớp nên phụ thuộc vào một số tham số khác, hãy nói rằng đó là giá trị của T::value:

template <typename T, typename... Args, typename Enable> 
class A; 

template <typename T, typename... Args, typename = typename std::enable_if<T::value>::type> 
class A 
{ 
    // do something 
}; 

template <typename T, typename... Args, typename = typename std::enable_if<!T::value>::type> 
class A 
{ 
    // do something else 
}; 

int main() { return 0; } 

Tuy nhiên, chương trình này cung cấp lỗi sau:

prog.cpp:6:11: error: parameter pack ‘Args’ must be at the end of the template parameter list class A;

Tôi đã cố gắng tìm một nguồn thông tin tốt về việc sử dụng enable_if để chọn các lớp có mẫu variadic. Câu hỏi duy nhất tôi có thể tìm được cái này:

How to use std::enable_if with variadic template

Nhưng bất chấp tên, câu hỏi này và câu trả lời của nó là không thể giúp ích nhiều. Nếu ai đó có thể cung cấp hoặc liên kết một hướng dẫn về cách thức này nên được tiếp cận và tại sao điều đó sẽ được đánh giá cao.

Trả lời

8

Trước hết, những gì bạn đang cố gắng đang viết nhiều định nghĩa của một mẫu lớp. Điều đó không được phép vì vi phạm quy tắc Một định nghĩa. Nếu bạn muốn bật điều kiện với các lớp học, bạn cần chuyên môn. Ngoài ra, thông báo lỗi trình biên dịch đã cho bạn biết, bạn không thể có gói tham số variadic ở giữa danh sách tham số.

Một cách để làm điều đó sẽ là:

namespace detail { 

template<typename T, typename Enable, typename... Args> 
class A_impl; 

template<typename T, typename... Args> 
class A_impl<T, typename std::enable_if<T::value>::type, Args...> { 
    // code here 
}; 

template<typename T, typename... Args> 
class A_impl<T, typename std::enable_if<!T::value>::type, Args...> { 
    // code here 
}; 
} 

template<typename T, typename...Args> 
class A : public detail::A_impl<T, void, Args...> {}; 

Jonathan's way cũng là hoàn toàn tốt đẹp nếu tình trạng này thực sự là một bool, nhưng nó có thể không thể hữu ích nếu bạn muốn bổ sung thêm các chuyên ngành mà mỗi phụ thuộc vào nhiều conditons.

+0

Tôi đã cố gắng khai báo 'A a;', nhưng trình biên dịch vẫn nói với tôi: "instantiation implicit của undefined template' chi tiết :: A_impl 'Tôi rất cảm kích nếu bạn có thể giải thích điều này một chút. (Xin lỗi tôi vẫn đang học những thứ này) – astroboylrx

+0

@astroboylrx Để làm việc này, đầu tiên gõ vào danh sách tham số mẫu của 'A' cần phải có một' giá trị' thành viên, bởi vì kiểm tra trong 'enable_if' phụ thuộc vào nó.Bạn đã sử dụng' float' thay vào đó.Không có 'giá trị' thành viên, các kiểm tra trong' enable_if' không hợp lệ, do đó, mẫu chính của 'A_impl' (nó không có triển khai thực hiện, nó chỉ được khai báo) được chọn và bạn nhận được lỗi. – jrok

+0

Xin lỗi vì trả lời trễ của tôi. Cảm ơn bạn đã giải thích này. Tôi thấy nó bây giờ. :-) – astroboylrx

9

Có vẻ như mục đích của bạn, bạn không cần phải kích hoạt/vô hiệu hóa các lớp, bạn chỉ cần một đặc tả từng phần:

template <typename T, bool B = T::value, typename... Args> 
    class A; 

template <typename T, typename... Args> 
    class A<T, true, Args...>; 

template <typename T, typename... Args> 
    class A<T, false, Args...>; 
+1

Vì vậy, bạn phải cung cấp 'b' cách thủ công khi bạn cung cấp 'Args' ... – Jarod42

+3

Tôi nghĩ rằng việc sử dụng [mẫu bí danh như ở đây] (http://coliru.stacked-crooked.com/a/524efebedc6a4d1c) là gần hơn với những gì OP muốn –

+0

Vâng, thật đơn giản để sau đó bọc nó vào một bí danh để làm cho nó thân thiện với người dùng hơn –

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