Pytanie: która specjalizacja powinna być używana pod numerem foo<std::unique_ptr<int>>
?
Należy zauważyć, że int
nie jest klasą, więc wartość std::is_class<T>::value
jest fałszywa, a wersja A
nie pasuje.
Jeśli chcesz, że wersja A
jest zawsze stosowany, gdy pierwszy parametr szablonu jest std::unique_ptr
, można napisać wersję A
jak
template <typename T>
struct foo<std::unique_ptr<T>,
typename std::enable_if<std::is_class<
std::unique_ptr<T>>::value>::type>
{ static int const value = 1; };
lub można napisać foo
następująco
template <typename T,
typename = typename std::enable_if<std::is_class<T>::value>::type>
struct foo;
template <typename T>
struct foo<std::unique_ptr<T>>
{ static int const value = 1; };
template <typename T>
struct foo<T>
{ static int const value = 2; };
Więc A
stanie się bardziej wyspecjalizowaną wersją niż B
i Twój kod może się skompilować. W przeciwnym razie wersja A
jest w rzeczywistości bardziej wyspecjalizowaną wersją niż ta, którą kompilator jej nie rozpoznaje.
Zauważmy, że z
template <typename T>
struct foo<std::unique_ptr<T>,
typename std::enable_if<std::is_class<
std::unique_ptr<T>>::value>::type>
{ static int const value = 1; };
kompilacji kodu i że std::is_class<std::unique_prt<T>>::value
jest kiedykolwiek true; ale jeśli piszesz
template <typename T>
struct foo<std::unique_ptr<T>,
typename std::enable_if<true>::type>
{ static int const value = 1; };
(który w rzeczywistości jest równoważna) kod nie kompiluje
- Edit -
Jeśli chcesz takim przypadku foo<std::unique_ptr<int>
mecz B
, (na przykładzie) można utworzyć cechy typu następująco
struct foo<T>
{ static int const value = 2; };
template <typename T>
struct proValue
: std::integral_constant<int, 2>
{ };
template <typename T>
struct proValue<std::unique_ptr<T>>
: std::integral_constant<int, std::is_class<T>::value ? 1 : 2>
{ };
i zdefiniować jako foo
Wynika
template <typename T, int = proValue<T>::value>
struct foo;
template <typename T>
struct foo<std::unique_ptr<T>, 1>
{ static int const value = 1; };
template <typename T>
struct foo<T, 2>
{ static int const value = 2; };
Poniżej znajduje się pełny compilable przykład
#include <memory>
#include <vector>
#include <iostream>
#include <type_traits>
class Test
{ };
template <typename T,
typename = typename std::enable_if<std::is_class<T>::value>::type>
struct foo;
template <typename T>
struct foo<std::unique_ptr<T>>
{ static int const value = 1; };
template <typename T>
struct foo<T>
{ static int const value = 2; };
template <typename T>
struct proValue
: std::integral_constant<int, 2>
{ };
template <typename T>
struct proValue<std::unique_ptr<T>>
: std::integral_constant<int, std::is_class<T>::value ? 1 : 2>
{ };
template <typename T, int = proValue<T>::value>
struct bar;
template <typename T>
struct bar<std::unique_ptr<T>, 1>
{ static int const value = 1; };
template <typename T>
struct bar<T, 2>
{ static int const value = 2; };
int main()
{
std::cout << foo<std::vector<int>>::value << '\n'; // print 2
std::cout << foo<std::unique_ptr<int>>::value << '\n'; // print 1
std::cout << foo<std::unique_ptr<Test>>::value << '\n'; // print 1
std::cout << bar<std::vector<int>>::value << '\n'; // print 2
std::cout << bar<std::unique_ptr<int>>::value << '\n'; // print 2
std::cout << bar<std::unique_ptr<Test>>::value << '\n'; // print 1
}
Cóż, dwie instrukcje 'std :: enable_if' powinny być komplementarne, prawda? –
Wygląda na to, że może to rozwiązać, ale moje zrozumienie "bardziej wyspecjalizowanych" zasad powinno uczynić to niepotrzebnym. – Arelius