2013-07-24 8 views
6

Próbuję znaleźć typ A w opakowaniu parametrów:znaleźć w opakowaniu typu parametru

template <int I, typename A, typename B, typename ...C> 
struct index_of 
{ 
    static constexpr int const value = 
    std::is_same<A, B>::value ? I : index_of<I + 1, A, C...>::value; 
}; 

template <int I, typename A, typename B> 
struct index_of<I, A, B> 
{ 
    static constexpr int const value = 
    std::is_same<A, B>::value ? I : -1; 
}; 

To wydaje się działać, ale nie jestem w stanie wyeliminować parametr nietypowe I, które chciałbym być parametrem domyślnym, ale nie może tego zrobić, z powodu pakietu parametrów na końcu. Jak wyeliminować/ukryć I, aby metafunkcja stała się bardziej przyjazna dla użytkownika?

Odpowiedz

3
template <typename A, typename B, typename... C> 
struct index_of 
{ 
    static constexpr int const value = 
    std::is_same<A, B>{} 
    ? 0 
    : (index_of<A, C...>::value >= 0) ? 1+index_of<A, C...>::value : -1; 
}; 

template <typename A, typename B> 
struct index_of<A, B> 
{ 
    static constexpr int const value = std::is_same<A, B>{} -1; 
}; 

Uwaga: std::is_same<A, B>{} -1 używa konwersji z bool na int.


lepiej wynikające z integral_constant:

template <typename A, typename B, typename... C> 
struct index_of 
    : std::integral_constant 
    < int, 
     std::is_same<A, B>{} 
     ? 0 
     : (index_of<A, C...>{} == -1 ? -1 : 1+index_of<A, C...>{}) 
    > 
{}; 

template <typename A, typename B> 
struct index_of<A, B> 
    : std::integral_constant < int, std::is_same<A, B>{} -1 > 
{}; 

Jeśli nie trzeba zwracać -1 w przypadku, gdy nie zostanie znaleziony typ: (jeśli ktoś wie jak do włączenia static_assert tutaj, aby uzyskać ładną wiadomość diagnostyczną, byłbym wdzięczny za komentarz/edycję)

template <typename A, typename B, typename... C> 
struct index_of 
    : std::integral_constant < std::size_t, 
          std::is_same<A, B>{} ? 0 : 1+index_of<A, C...>{} > 
{}; 

template <typename A, typename B> 
struct index_of<A, B> 
    : std::integral_constant<std::size_t, 0> 
{ 
    constexpr operator std::size_t() const 
    { 
     return std::is_same<A, B>{} 
       ? 0 
       : throw std::invalid_argument("Type not found!"); 
    } 
}; 
+0

Ale druga i trzecia metafunkcja nie obsługuje poprawnie duplikatów. – user1095108

+0

@ user1095108 Masz rację, uprościłem to. Naprawiony. – dyp

6

Można ukryć to wdrożenie w obszarze nazw i skorzystać z innej klasy, która wywołuje implementację o przykład domyślna parametru:

namespace detail 
{ 
    // your code as it is in the question 
} 

template <typename A, typename... B> 
struct index_of 
{ 
    static int const value = detail::index_of<0, A, B...>::value; 
}; 

Edytuj

W swoim komentarzu DYP sugeruje prostszą drogę do domyślnych I używając aliasu

template <typename A, typename... B> 
using index_of = detail::index_of<0, A, B...>; 
+2

W C++ 11 można nawet użyć szablonu aliasu. – dyp

Powiązane problemy