c++ - 匹配可变参数非类型模板

标签 c++ templates c++14 variadic-templates non-type

假设我有两个结构,FooBar :

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

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

我想创建一个类型特征(称为 match_class ),如果我通过两个 Foo<...> 则返回 true类型或两种 Bar<...>类型,但如果我尝试混合它们则为假:

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; };

或者对此有一个外部特征。然后显式写出所有内容 - 如果两个类模板具有相同的非类型模板参数 and 则它们匹配,那么它们也具有相同的类模板,按此顺序:

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] 包含:

A template type argument cannot be deduced from the type of a non-type template-argument. [Example:

template<class T, T i> void f(double a[10][i]);
int v[10][20];
f(v); // error: argument for template-parameter T cannot be deduced

-end example]

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

When the value of the argument corresponding to a non-type template parameter P that is declared with a dependent type is deduced from an expression, the template parameters in the type of P are deduced from the type of the value. [ Example:

template<long n> struct A { };

template<typename T> struct C;
template<typename T, T n> struct C<A<n>> {
  using Q = T;
};

using R = long;
using R = C<A<2>>::Q;           // OK; T was deduced to long from the
                                // template argument value in the type A<2>

— end example ] The type of N in the type T[N] is std​::​size_­t. [ Example:

template<typename T> struct S;
template<typename T, T n> struct S<int[n]> {
  using Q = T;
};

using V = decltype(sizeof 0);
using V = S<int[42]>::Q;        // OK; T was deduced to std​::​size_­t from the type int[42]

— end example ]

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

相关文章:

c++ - Windows GTest EXPECT_STREQ : error: no matching function for call to 'CmpHelperSTREQ'

c++ - 错误 : expected constructor, 析构函数,或 ‘&’ token 之前的类型转换

C++: Client-Server 分布式处理思想,发送数据后关闭连接,任务完成后重新打开?

c++ - 在递归模板中通过引用传递模板函数

c++ - 错误: expected class-name before ‘{’ token with templates

C++显式整数用户自定义转换

c++ - rand() 在编译时生成相同的数字

c++ - unique_ptr 作为模板参数

c++ - 折叠表达式是 C++14 还是 C++1z 特性?

c++ - 我可以在带有值初始化的 header 中使用 static const float