2015-09-08 15 views
7

Tôi có hàm mẫu trong đó loại enum được chuyển thành loại cơ bản của nó hoạt động tốt, nhưng tôi đã viết quá tải phải lấy số nguyên và tự trả về một lỗi mà int không phải là kiểu liệt kê. Trong mẫu của tôi, điều này cần phải được lọc ra. Chuyện gì thế?"Chuyển đổi" từ loại này sang loại tương tự gây ra lỗi

Dưới đây là các mẫu mã:

template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
    { 
     return t; 
    } 

    template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value, typename std::underlying_type<TT>::type>::type 
    { 
     return (typename std::underlying_type<TT>::type)t; 
    } 

Demo

+1

Tôi không biết nếu 'underlying_type' là SFINAE thân thiện, nhưng có một [workaround] (http://coliru.stacked-crooked.com/a/e7f1dd3b75c8d9c2) cho rằng –

+0

gì? Tôi thấy nó hoạt động, nhưng những gì đang xảy ra ở đây mà làm cho nó hoạt động? Và tại sao sẽ không 'internal_type' bởi SFINAE thân thiện? – Adrian

+1

Sự khởi tạo của 'std :: bases_type :: type' được hoãn lại, do đó' enable_if' có thể bị lỗi trước. Bởi * SFINAE thân thiện * Tôi có nghĩa là bất kỳ sự thay thế nào xảy ra chỉ trong bối cảnh ngay lập tức (nếu nó xảy ra bên trong 'inner_type' chính nó không phải là SFINAE thân thiện). –

Trả lời

4

std::underlying_type<TT>::type đang được đánh giá trong std::enable_if mặc dù std::is_enum<TT>::valuefalse như false không phải là một lỗi. Vì một kiểu liệt kê không được đánh giá, nó gây ra lỗi. Nếu chúng ta di chuyển SFINAE vào các tham số mẫu, chúng ta có thể nhận được tình trạng quá tải mong muốn và vẫn trả về đúng loại.

template <typename TT, typename std::enable_if<!std::is_enum<TT>::value, TT>::type* = nullptr> 
static constexpr auto get_value(TT t) -> TT 
{ 
    return t; 
} 

template <typename TT, typename std::enable_if<std::is_enum<TT>::value>::type* = nullptr> 
static constexpr auto get_value(TT t) -> typename std::underlying_type<TT>::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

Bạn có thể nhìn thấy nó làm việc trong này Live Example

+0

Vì vậy, để đảm bảo rằng tôi hiểu chính xác điều này, tham số mẫu thứ 2 là thông số chưa được đặt tên của loại 'void *' nếu là/không phải là kiểu enum (tùy thuộc vào thứ tôi muốn) dẫn đến việc tạo và một thực thể không nếu không phải những gì tôi muốn và sau đó sẽ bị từ chối? – Adrian

+0

@Adrian Nếu 'std :: enable_if' thành công' loại' bị vô hiệu và sau đó chúng tôi có thể đặt con trỏ của loại thành 'nullptr' cho SFINAE – NathanOliver

+0

@dyp Tôi đã chỉnh sửa câu trả lời. Nó sẽ giải quyết nguyên nhân thực sự ngay bây giờ. – NathanOliver

4

Bằng cách cố gắng để nhanh chóng std::underlying_type<T> với T đó không phải là một kiểu enum, bạn đang vi phạm một yêu cầu rằng các tiêu chuẩn áp đặt trên mẫu tham số T:

§ 20.10.7.6 [meta.trans.other]/Bảng 57:

 Template   |   Condition   |  Comments 
------------------------+---------------------------+----------------------- 
template <class T>  | T shall be an enumeration | The member typedef 
struct underlying_type; | type (7.2)    | type shall name 
         |       | the underlying type 
         |       | of T. 

Dưới đây là một phương pháp thay thế nếu người ta không muốn bất kỳ mẫu tham số bổ sung:

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
{ 
    return t; 
} 

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value 
          , std::underlying_type<TT> 
       >::type::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

Bằng cách này, instantiation của std::underlying_type<TT> được hoãn lại cho đến khi tình trạng std::enable_if đánh giá để true, bởi vì một lồng nhau type định nghĩa được yêu cầu cho số tiền trả lại std::enable_if<B,T>::type.

DEMO

+0

Vì vậy, yêu cầu chỉ cần thiết nếu bạn nhận được loại 'std :: bases_type :: type' nhưng không cần thiết cho' std :: bases_type '? Tại sao vậy? – Adrian

+1

@Adrian 'std :: bases_type ' không được khởi tạo khi chỉ được sử dụng làm đối số mẫu loại –

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