嵌套结构的专业化特征

Specialization traits of nested struct

我有一个带有嵌套模板结构的模板结构。

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?

中的代码中缺少什么

What I'm missing in code where bar declaration is in 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:: 之前,因此无法推导。

您可以定义此部分专业化,但从未使用过。

用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_tstd::declval...

测试所需成员的存在应该不那么难看