繁体   English   中英

如何明确地将某些模板化输入作为 arguments?

[英]How to explicitly take in certain templated inputs as arguments?

我有Foo<a, b>Foo<c, d> ,其中Foo接受 2 个模板化参数。 如果我有一个带有 class SomeFunction的可变参数模板,它接受这些Foo输入,如下所示:

template <typename... Ts>
class SomeFunction< /*some input*/ >

我该怎么做才能确保SomeFunction只接受Foo模板而不接受其他模板,例如Blah<a,b>

除非 arguments 类型正确,否则您可以让您的类型私下继承自另一个无法实例化的类型。 您将模板类型保留为未定义,然后部分专门化Foo<...>情况,与列表的其余部分一起递归。

// Base template forward declaration, but note we don't define it.
template <typename...>
struct foo_validator;

// Specialization handling the terminating case.
template <>
struct foo_validator<> {};

// Partial specialization, handling Foo<a, b> followed by anything.  Note in particular
// how it inherits itself with the remainder of the type arguments.
template <typename T1, typename T2, typename ...Tail>
struct foo_validator<Foo<T1, T2>, Tail...> : foo_validator<Tail...> {};

// Now have SomeFunction privately inherit this type.
template <typename ...Ts>
class SomeFunction : private foo_validator<Ts...> {};

如果您传递除Foo<A, B> (其中AB可以是任何类型)之外的任何类型 arguments ,那么任何特化都不会匹配,编译器将尝试实例化未特化的模板。 因为没有定义,所以会导致编译错误。

本声明:

SomeFunction<Foo<int, float>, std::pair<short, double>> a;

将失败:

error: invalid use of incomplete type 'struct foo_validator<std::pair<short int, double> >'


另一种方法非常相似,使用static_assert

// As before, this is the failing case, but we define it to inherit
// std::false_type.
template <typename...>
struct foo_validator : std::false_type {};

// The empty case is success and inherits std::true_type.
template <>
struct foo_validator<> : std::true_type {};

// Again, the "so-far-successful" partial specialization.
template <typename T1, typename T2, typename ...Tail>
struct foo_validator<Foo<T1, T2>, Tail...> : foo_validator<Tail...> {};

// Instead of inheriting foo_validator, we assert on its value member.
template <typename ...Ts>
class SomeFunction {
    static_assert(foo_validator<Ts...>::value, "All type arguments must be Foo<,>");
};

现在SomeFunction的错误实例化将失败:

error: static assertion failed: All type arguments must be Foo<,>


这是如何运作的? 我们在这两种方法中都有三个声明,它们在两种方法中都扮演相同的角色:

  1. 我们声明一个接受任何类型 arguments 作为失败案例的模板。
  2. 我们针对没有类型 arguments 的情况声明此模板的特化作为成功案例(空虚的事实)。
  3. 当第一个参数是具有两个类型参数的Foo模板类型的实例化,然后是任意数量(零个或多个)其他类型参数时,我们声明了一个部分特化。 此类型继承验证器模板类型,但删除了第一个类型参数(递归)。

让我们看一个尝试实例化SomeFunction<Foo<int, int>, Foo<float, double>>的示例。

  1. 编译器尝试实例化foo_validator<Foo<int, int>, Foo<float, double>> 这与上面列表中的部分专业化类型 3 匹配。 ( T1 = int, T2 = int, Tail = [Foo<float, double>] ) 这种类型继承foo_validator<Foo<float, double>>
  2. 编译器尝试实例化foo_validator<Foo<float, double>> 这也与上面列表中的部分专业化类型 3 匹配。 ( T1 = float, T2 = double, Tail = [] ) 这种类型继承foo_validator<>
  3. 编译器尝试实例化foo_validator<>并找到完全匹配的特化,即上面列表中的类型 2。 在“继承foo_validator ”方法中,没有任何反应,编译继续进行。 static_assert方法中,此类型继承std::true_type ,因此断言成功。

现在让我们看一个不应该工作的类型: SomeFunction<Foo<int, int>, std::pair<float, double>>

  1. 编译器尝试实例化foo_validator<Foo<int, int>, std::pair<float, double>> 这与上面列表中的部分专业化类型 3 匹配。 ( T1 = int, T2 = int, Tail = [std::pair<float, double>] ) 这种类型继承foo_validator<std::pair<float, double>>
  2. 编译器尝试实例化foo_validator<std::pair<float, double>> 这与上面列表中的类型 2 或 3 不匹配,因此编译器尝试实例化基本模板声明(类型 1)。 在“ foo_validator方法”中,这会失败,因为模板类型不完整(我们从未定义过它)。 static_assert方法中,基模板被实例化并继承std::false_type ,因此断言失败。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM