2016-10-13 4 views
2

У меня есть следующая проблема:элемента в зависимости от параметра шаблона

template< typename T, size_t N, size_t... N_i > 
class A 
{ 
    public: 

    // ... 

    // first implementation 
    template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M!=1, size_t >::type = 0 > 
    A<T, N_i...> operator[](size_t i) 
    { 
     A< T, N_i... > res{ ... }; 

     return res; 
    } 

    // second implementation 
    template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M==1, size_t >::type = 0 > 
    T operator[](size_t i) 
    { 
     return ... ; 
    } 
}; 

Как вы можете видеть выше, я пытаюсь реализовать класс A, который ожидает в качестве аргументов шаблона типа T (например int или float) и sizeof...(N_i)+1 -many size_t.

В зависимости от количества пройденных size_t (т.е. sizeof...(N_i)+1), я буду использовать другую реализацию для функции члена operator[](size_t) с другим типом результата:

  • одна реализации для случая sizeof...(N_i)+1 > 1 с возвращаемым типом A < T, N_i... > (называемой «первой реализацией» в коде)
  • и один для футляра sizeof...(N_i)+1 == 1 с обратным типом T (именуемый как «вторая реализация» в коде).

К сожалению, я не знаю, как это можно реализовать - решение выше не работает. У кого-нибудь есть идея?

Большое спасибо заранее.

ответ

2

A<T, N_i...> является недопустимым для пустого N_i. Как решить эту проблему, вы можете использовать окольные:

template <typename, std::size_t ...> 
struct PopFrontA 
{ 
    using type = void; // Dummy type for A<T, N> 
}; 

template< typename T, std::size_t N, std::size_t... N_i > class A; 

template <typename T, std::size_t N, std::size_t N2, std::size_t ... Ns> 
struct PopFrontA<T, N, N2, Ns...> 
{ 
    using type = A<T, N2, Ns...>; 
}; 

template <typename T, std::size_t ... Ns> 
using PopFrontA_t = typename PopFrontA<T, Ns...>::type; 

А потом

// first implementation 
template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M!=1, size_t >::type = 0 > 
PopFrontA_t<T, N, N_i...> 
operator[](size_t i) 
{ 
    A< T, N_i... > res{ /*...*/ }; 

    return res; 
} 

Demo

+0

Спасибо! Вы знаете, почему 'A ' не вызывает ошибку SFINAE для пустого 'N_i'? –

+1

@abraham_hilbert: 'A ' не зависит от параметра шаблона метода. 'A ' недействителен для любого значения параметра шаблона метода. – Jarod42

2

Если вы изменяете

A< T, N_i... > res{ ... }; 

в

A< T, N_i... > res{ }; 

и

return ... ; 

в

return T{} ; 

недостаточно?

--- EDIT ---

No: (спасибо!), Как указал на Jarod42, не достаточно.

Поэтому я предлагаю следующее решение, на основе класса специализации шаблона и std::conditional, чтобы избежать использования SFINAE

#include <iostream> 
#include <type_traits> 

template< typename, size_t...> 
class A; 

template< typename T, size_t N, size_t... N_i > 
class A<T, N, N_i...> 
{ 
    public: 
     template <typename Next = typename std::conditional<sizeof...(N_i), 
              A<T, N_i...>, T>::type> 
     Next operator[] (size_t i) 
     { return Next{}; } 
}; 

int main(int argc, char* argv[]) 
{ 
    A<int, 2, 4> a; 

    std::cout << a[1][2] << std::endl; 

    return 0; 
} 

Если вы не хотите специализироваться A, вы можете добавить вложенную-структуру из A в делайте грязную работу.

#include <iostream> 
#include <type_traits> 

template< typename T, size_t N, size_t... N_i > 
class A 
{ 
    template <typename U, size_t ... O_i> 
     struct Next 
     { using type = A<U, O_i...>; }; 

    template <typename U> 
     struct Next<U> 
     { using type = U; }; 

    public: 
     using next_t = typename Next<T, N_i...>::type; 

     next_t operator[] (size_t i) 
     { return next_t{}; } 
}; 

int main(int argc, char* argv[]) 
{ 
    A<int, 2, 4> a; 

    std::cout << a[1][2] << std::endl; 

    return 0; 
} 
+0

У вас будет ошибка, когда вы экземпляр '' A . [Демо] (http://coliru.stacked-crooked.com/a/70c3a96907dc600f) – Jarod42

+0

@ Jarod42 - D'oh! Ты прав; Благодарю. – max66

Смежные вопросы