2017-07-31 15 views
6

Tôi có typename T1 và tôi có gói tham số typename... Variadic.Cấu trúc chứa bí danh cho loại chuyển đổi đầu tiên của gói có thể biến đổi là

Tôi muốn tạo cấu trúc chứa bí danh sử dụng using Type = ... cho loại đầu tiên trong gói thông số T1 có thể được chuyển đổi thành. Cho đến nay tôi đã thử như sau:

template<typename T1, typename T2, typename... Variadic> 
struct VariadicConvertibleType 
{ 
    using Type = std::enable_if<std::is_convertible<T1, T2>::value, T2>::type; 
}; 

Đây có thể là một giải pháp tiềm năng sử dụng SFINAE cho hai loại đầu tiên, nhưng tôi cần phải mở rộng này cho tất cả các loại trong gói sử dụng đệ quy. Tất cả các nỗ lực của tôi đã thất bại cho đến nay, bởi vì bạn không thể đặt điều kiện vào việc sử dụng các khai báo bí danh. Nếu không, điều gì đó tương tự như vậy có thể được sử dụng:

template<typename T1, typename T2, typename... Variadic> 
struct VariadicConvertibleType 
{ 
    using Type = std::is_convertible<T1, T2>::value ? T2 : VariadicConvertibleType<T1, Variadic...>::Type; 
}; 

Tôi có thể sử dụng mọi thứ (và bao gồm) C++ 14 để triển khai giải pháp. Tôi không thể sử dụng bất cứ điều gì khác hơn là thư viện đứng.

+2

http://en.cppreference.com/w/cpp/types/conditional có thể? Và trường hợp cơ bản nào không có loại tương thích? – LogicStuff

Trả lời

4

Bạn có thể sử dụng std::conditional, như thế này:

template<typename T1, typename T2, typename... Variadic> 
struct VariadicConvertibleType 
{ 
    using type = std::conditional_t<std::is_convertible<T1, T2>::value, T2, typename VariadicConvertibleType<T1, Variadic...>::type>; 
}; 

template<typename T1, typename T2> 
struct VariadicConvertibleType<T1, T2> 
{ 
    static_assert(std::is_convertible<T1, T2>::value); 
    using type = T2; 


    // Alternative base-case 
    // using type = std::conditional_t<std::is_convertible<T1, T2>::value, T2, T1>; 
}; 

tôi đã cung cấp hai cơ sở-trường hợp (thay thế một trong comment). Điều chính (mà tôi điều là những gì bạn muốn) sử dụng một (C++ 14) static_assert nếu T1 không thể chuyển đổi thành bất kỳ loại nào trong số Variadic. Trường hợp cơ sở thay thế đặt type thành T1 trong trường hợp đó.

thử nghiệm

#include <iostream> 
#include <type_traits> 
#include <typeinfo> 

int main() 
{ 
    using my_type_1 = typename VariadicConvertibleType<int, double, float>::type; 
    std::cout << typeid(my_type_1).name() << '\n'; // double 

    using my_type_2 = typename VariadicConvertibleType<int, int*, float>::type; 
    std::cout << typeid(my_type_2).name() << '\n'; // float 

    using my_type_3 = typename VariadicConvertibleType<int, int*, float*>::type; 
    std::cout << typeid(my_type_3).name() << '\n'; // Complile error with the primary base-case, and int with the alternative base-case. 
} 
+1

Giải pháp 'static_assert' dường như không hoạt động đối với tôi, nhưng giải pháp cơ bản thay thế. Thanh danh. – PandarinDev

0

Vấn đề với std::conditional là nó đòi hỏi cả các loại bạn ăn nó để được xác định rõ. Để phá vỡ điều đó, bạn cần phải giới thiệu một loại indirection trong tiến trình.

Để làm như vậy, chúng tôi sẽ có mẫu trình trợ giúp được cung cấp boolean, sẽ xác định loại hoặc quay trở lại thành phần tiếp theo.

namespace details { 

template <bool B, typename T, typename... Args> 
struct FirstConvertibleImpl; 

template <typename T, typename U, typename... Args> 
struct FirstConvertibleImpl<true, T, U, Args...> { 
    using type = U; 
}; 

template <typename T, typename U, typename V, typename... Args> 
struct FirstConvertibleImpl<false, T, U, V, Args...> { 
    using type = typename FirstConvertibleImpl<std::is_convertible<T, V>::value, T, V, Args...>::type; 
}; 

} 

Nếu các loại cho không dẫn đến chuyển đổi có hiệu lực, điều này rõ ràng là sẽ phát hành một lỗi như chúng ta không quan tâm để xác định trường hợp "không hợp lệ" (FirstConvertibleImpl<false, T1, T2> không có người thực hiện đối với bất kỳ loại T1, T2)

Bây giờ chúng ta tạo ra một giao diện mức cao hơn đối với việc sử dụng rõ ràng hơn:

template <typename T, typename... Args> 
struct FirstConvertibleInPack; 

template <typename T, typename U, typename... Args> 
struct FirstConvertibleInPack<T, U, Args...> { 
    using type = typename details::FirstConvertibleImpl<std::is_convertible<T, U>::value, T, U, Args...>::type; 
}; 

một lần nữa, chúng tôi không quan tâm để xác định các trường hợp Args... = [] vì những trường hợp này đều vô hình thành anyway.

Có thể tìm thấy Live Demo trên Coliru.

Tất nhiên bạn có thể trừu tượng sâu hơn và làm cho ví dụ này chung chung hơn bằng cách cho phép áp dụng bất kỳ đặc điểm nhị phân nào bạn ưa thích.

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