假设我有两种结构,FooBar:

template<int...>
struct Foo{};

template<unsigned long...>
struct Bar{};

我想创建一个类型特征(称为match_class),如果我传递两种Foo<...>类型或两种Bar<...>类型,则返回true,但如果我尝试将它们混合使用,则返回false:
int main()
{
    using f1 = Foo<1, 2, 3>;
    using f2 = Foo<1>;
    using b1 = Bar<1, 2, 3>;
    using b2 = Bar<1>;
    static_assert(match_class<f1, f2>::value, "Fail");
    static_assert(match_class<b1, b2>::value, "Fail");
    static_assert(!match_class<f1, b1>::value, "Fail");
}

对于C++ 1z(clang 5.0.0和gcc 8.0.0),只需执行此操作(Demo):
template<class A, class B>
struct match_class : std::false_type{};

template<class T, template<T...> class S, T... U, T... V>
struct match_class<S<U...>, S<V...>> : std::true_type{};

但是在C++ 14中,出现以下错误(相同的编译器* Demo):
error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used [-Wunusable-partial-specialization]
struct match_class<S<U...>, S<V...>> : std::true_type{};
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: non-deducible template parameter 'T'
template<class T, template<T...> class S, T... U, T... V>

问题:在C++ 14中对此有什么解决方法?

理想情况下,用于测试类型特征的语法应保持不变。

次要问题: C++ 14的行为正确吗? (或者是我未看到C++ 17的行为吗?)

*请注意,MSVC 19.00.23506具有相同的故障Demo

最佳答案

在C++ 14中,您无法通过以下方式推断出T:

template<class T, template<T...> class S, T... U, T... V>
struct match_class<S<U...>, S<V...>> : std::true_type{};

但是在C++ 17中,您可以。您看到的行为是正确的。

在C++ 14中,由于无法推断出T,因此需要一种显式提供它的方法。因此,您可能需要类模板本身来指示其非类型模板参数类型:
template <int...> struct Foo { using type = int; };
template <unsigned long...> struct Bar { using type = unsigned long; };

或对此具有外部特征。然后显式地写出所有内容-如果两个类模板具有相同的非类型模板参数,然后又具有相同的类模板,则它们按以下顺序匹配:
template <class... Ts> struct make_void { using type = void; };
template <class... Ts> using void_t = typename make_void<Ts...>::type;

template <class T1, class T2, class A, class B>
struct match_class_impl : std::false_type { };

template <class T, template <T...> class S, T... U, T... V>
struct match_class_impl<T, T, S<U...>, S<V...>> : std::true_type{};

template <class A, class B, class=void>
struct match_class : std::false_type { };

template <class A, class B>
struct match_class<A, B, void_t<typename A::type, typename B::type>>
    : match_class_impl<typename A::type, typename B::type, A, B>
{ };

这是添加对 template auto 的支持的结果。在C++ 14中,[temp.deduct.type]包含:



但是在C++ 17中,它是now reads:

关于c++ - 匹配可变参数非类型模板,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44263503/

10-11 22:57
查看更多