2013-06-07 27 views
16

Vấn đề này đã được thảo luận một vài lần nhưng tất cả các giải pháp tôi đã tìm thấy hoặc không hoạt động hoặc được dựa trên khẳng định tĩnh của boost. Vấn đề của tôi rất đơn giản. Tôi có một lớp, và tôi chỉ muốn cho phép các loại thực (double và float). Tôi muốn một lỗi biên dịch thời gian nếu tôi cố gắng để nhanh chóng lớp với một loại khác hơn là nổi hoặc tăng gấp đôi. Tôi đang sử dụng Visual C++ 11. Dưới đây là những gì tôi đã thử:Làm cách nào để hạn chế một lớp mẫu đối với các loại được cài sẵn nhất định?

template <typename RealType> 
class A 
{ 
    // Warning C4346 
    static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value); 
} 


template <typename RealType> 
class A 
{ 
    // Error C2062: type 'unknown' unexpected 
    static_assert(decltype(RealType) == double || decltype(RealType) == float); 
} 

Bất kỳ ý tưởng nào? Cảm ơn trước!

+1

Câu hỏi thứ nhất là, nó quan trọng? Nếu bạn khởi tạo mẫu với một kiểu khác, và kiểu này không thể được xử lý theo cách khuôn mẫu mong đợi để xử lý nó, việc biên dịch sẽ thất bại. Và nếu nó có thể, cho phép * chỉ * hai loại đó có hiệu quả ngoài vòng pháp luật ... nói ... một kiểu như BigDecimal. – cHao

+0

studio trực quan thực sự đưa ra cảnh báo khi static_assert không thành công và không phải là lỗi? Âm thanh như một con bọ. –

+0

Cũng thấy [mẫu C++ chỉ chấp nhận một số loại nhất định] (http://stackoverflow.com/q/874298/) và [Giới hạn tham số mẫu C++ thành lớp con] (http://stackoverflow.com/q/3175219).Chúng có trước C++ 11, nhưng chúng có thể tạo điểm đánh dấu tốt cho người khác. – jww

Trả lời

12

Một giải pháp mà tôi đã thấy là sử dụng std::enable_if trong bí danh loại. Một cái gì đó như:

using value_type = typename std::enable_if< 
        std::is_same<float, RealType>::value || 
        std::is_same<double, RealType>::value, 
        RealType 
       >::type; 

value_type chỉ tồn tại nếu RealType là chính xác float hoặc double. Nếu không, loại là không xác định và biên dịch không thành công.

Tôi muốn cảnh báo về việc quá nghiêm khắc với các loại. Các khuôn mẫu mạnh mẽ vì chúng một phần vì việc gõ vịt chúng có nghĩa là bất kỳ kiểu nào có thể được sử dụng theo cách bạn muốn sử dụng, sẽ hoạt động. Việc không cho phép các loại vì lợi ích của việc không cho phép các loại nói chung không giúp bạn đạt được nhiều thứ và có thể làm cho mọi thứ kém linh hoạt hơn so với chúng. Ví dụ: bạn sẽ không thể sử dụng loại có độ chính xác cao hơn, như loại thập phân lớn.

+0

Điều đó, và nếu bạn chỉ cần hai chuyên ngành, OO cũ và đa hình thời gian chạy có thể là một ý tưởng tốt hơn (ít nhất đáng xem xét). –

+0

SFINAE thực sự tốt khi bạn muốn tạo thêm chuyên môn của mẫu sau :) Tuy nhiên, nếu bạn chắc chắn sẽ không bao giờ có bất kỳ chuyên môn nào khác, 'static_assert' cho phép hiển thị các thông báo lỗi có ý nghĩa (vì SFINAE thường làm tổn thương mắt tôi). – Morwenn

26

Trong ví dụ đầu tiên của bạn, static_assert phải lấy tham số thứ hai sẽ là chuỗi ký tự, nếu không nó được coi là không thành công (chỉnh sửa: bỏ tham số thứ hai là hợp pháp kể từ C++ 17). Và đối số thứ hai này không thể được mặc định.

ví dụ thứ hai của bạn là không chính xác vì nhiều lý do:

  • decltype là để được sử dụng trên một biểu thức, chứ không phải trên một loại.
  • Bạn chỉ đơn giản là không thể so sánh các loại với ==, cách chính xác để làm điều này là những gì bạn thử trong lần thử đầu tiên với std::is_same.

Vì vậy, đúng cách để làm những gì bạn đang cố gắng để đạt được là:

#include <type_traits> 

template <typename RealType> 
class A 
{ 
    static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value, 
       "some meaningful error message"); 
}; 

Hơn nữa, tôi đặt cược bạn đang cố gắng co mẫu của bạn để điểm giá trị nổi. Để làm điều này, bạn có thể sử dụng các đặc điểm std::is_floating_point:

#include <type_traits> 

template <typename RealType> 
class A 
{ 
    static_assert(std::is_floating_point<RealType>::value, 
       "class A can only be instantiated with floating point types"); 
}; 

Và như một phần thưởng, chăm this online example.

5

Bằng cách này nó cũng cho phép chuyên môn hóa với nhiều loại hình:

template<typename T, typename Enable = void> 
class A { 
/// Maybe no code here or static_assert(false, "nice message"); 
}; 

/// This specialization is only enabled for double or float. 
template<typename T> 
class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> { 

}; 
+1

với 'static_assert (sai," thông điệp tốt đẹp ");' chương trình bị bệnh hình thành, không cần chẩn đoán. Xem http://stackoverflow.com/questions/30078818/static-assert-dependent-on-non-type-template-parameter-different-behavior-on-gc Vấn đề lúc đầu có vẻ phức tạp hơn, nhưng nguyên nhân gạch dưới là đơn giản như ví dụ của bạn. – bolov