2017-07-31 42 views
6

我有typename T1,我有一個參數包typename... Variadic包含替代包的第一個可轉換類型的別名的結構

我想創建一個結構,其中包含一個使用別名using Type = ...的第一個類型的參數包,T1可以轉換成。到目前爲止,我已經試過如下:

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

這可能是使用SFINAE對於前兩類潛在的解決方案,但我需要將此擴大到所有的包使用遞歸的類型。到目前爲止,我所有的嘗試都失敗了,因爲您不能將條件放入使用別名聲明中。否則,類似這樣的東西可以用來:

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

我可以用一切高達(包括)C++ 14實施解決方案。儘管如此,我不能使用其他任何東西。

+2

http://en.cppreference.com/w/cpp/types/conditional也許?什麼應該是沒有兼容類型的基本情況? – LogicStuff

回答

4

您可以使用std::conditional,像這樣:

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>; 
}; 

我提供了兩種基本情況(備選之一註釋)。 如果T1不能轉換爲Variadic中的任何類型,那麼主要(我想要的是什麼)使用(C++ 14)static_assert。在這種情況下,替代基本情況設置爲typeT1

測試

#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

'static_assert'解決方案似乎不適用於我,但替代的基本情況是。榮譽。 – PandarinDev

0

std::conditional的問題是,它同時需要你養活類型它被明確定義。爲了規避這一點,你需要在這個過程中引入一種間接性。

爲此,我們將有一個給定布爾值的助手模板,將定義類型或回退到下一個元素。

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; 
}; 

} 

如果給定的類型不導致有效的轉換,這顯然發出一個錯誤,因爲我們也沒在意界定「無效」的情況下(FirstConvertibleImpl<false, T1, T2>對任何類型的T1, T2沒有實現)

現在我們做出更清晰的使用更高級別的接口:

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; 
}; 

同樣,我們並不關心,以限定Args... = [],因爲這些案件反正病態的情況。

A Live Demo可以在Coliru上找到。

你當然可以抽象,甚至更深,並通過允許應用任何你喜歡的二進制特性使這個例子更通用。

相關問題