Особенности специализации вложенной структуры - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть структура шаблона с вложенной структурой шаблона.

template <int F>
struct foo
{
    template <int B>
    struct bar {
        static constexpr int f = F;
        static constexpr int b = B;
    };
 };

Я хочу создать такую ​​черту, как

template <class>
struct is_foo_bar : std::false_type { };

template <int F, int B>
struct is_foo_bar< foo<F>::bar<B> > : std::true_type { };

static_assert(is_foo_bar< foo<1>::bar<2> >::value);

Это выдает ошибку:

type/value mismatch at argument 1 in template parameter list for ‘template<class> struct is_foo_bar’<br>
struct is_foo_bar<foo<F>::bar<B>> : std::true_type { };

Если я возьму bar как

template <int F, int B>
struct foo_bar {
    static constexpr int f = F;
    static constexpr int b = B;
};

template <int F>
struct foo
{
    template <int B>
    using bar = foo_bar<F, B>;
};

template <class>
struct is_foo_bar : std::false_type { };

template <int F, int B>
struct is_foo_bar< foo_bar<F, B> > : std::true_type { };

static_assert(is_foo_bar< foo<1>::bar<2> >::value);

... это работает.Но я не хочу, чтобы это было так.Чего мне не хватает в коде, где bar объявление в foo?

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Используя SFINAE, это может быть решено следующим образом

template <class, class = void>
struct is_foo_bar : std::false_type { };

template <class T>
struct is_foo_bar< 
    T,
    std::enable_if_t<
        std::is_same_v< T, typename foo<T::f>::template bar<T::b> >
    >
> : std::true_type { };

Это работает, но вам нужно явно указать все аргументы, что может быть проблемой (например, для переменных).

РЕДАКТИРОВАТЬ : Найдена подсказка для вариативных аргументов

template <int F>
struct foo
{
    template <int B, class... Params>
    struct bar {
        static constexpr int f = F;
        static constexpr int b = B;
        static constexpr size_t size = sizeof...(Params);
    };
};

template <class, class = void>
struct is_foo_bar : std::false_type { };

template <template <int, class...> class T, int B, class... Params>
struct is_foo_bar<
    T<B, Params...>,
    std::enable_if_t<
        std::is_same_v<
            T<B, Params...>,
            typename foo< T<B, Params...>::f >::template bar<B, Params...>
        >
    >
> : std::true_type { };

template <int, class...>
struct not_foo_bar {
    static constexpr int f = 0;
};

static_assert(is_foo_bar< foo<1>::bar<2> >::value);
static_assert(is_foo_bar< foo<1>::bar<2, int> >::value);

static_assert(not is_foo_bar< not_foo_bar<1> >::value);
static_assert(not is_foo_bar< not_foo_bar<1, int> >::value);

Это гарантирует, что bar принадлежит foo.Когда такого требования нет, должно быть менее уродливо просто проверить наличие необходимых членов с std::void_t и std::declval ...

0 голосов
/ 25 февраля 2019

Чего мне не хватает в коде, где объявление bar находится в foo?

Вы забыли typename и template при написании частичной специализации

template <int F, int B>
struct is_foo_bar< typename foo<F>::template bar<B> > : std::true_type { };
// not deducible  ^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^  deducible context

, но реальная проблема заключается в том, что первое int значение шаблона, F, находится перед ::, поэтому не выводится.

Вы можете определить эту частичную специализациюно никогда не используется.

...