[英]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>
(其中A
和B
可以是任何类型)之外的任何类型 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<,>
这是如何运作的? 我们在这两种方法中都有三个声明,它们在两种方法中都扮演相同的角色:
Foo
模板类型的实例化,然后是任意数量(零个或多个)其他类型参数时,我们声明了一个部分特化。 此类型继承验证器模板类型,但删除了第一个类型参数(递归)。 让我们看一个尝试实例化SomeFunction<Foo<int, int>, Foo<float, double>>
的示例。
foo_validator<Foo<int, int>, Foo<float, double>>
。 这与上面列表中的部分专业化类型 3 匹配。 ( T1 = int, T2 = int, Tail = [Foo<float, double>]
) 这种类型继承foo_validator<Foo<float, double>>
。foo_validator<Foo<float, double>>
。 这也与上面列表中的部分专业化类型 3 匹配。 ( T1 = float, T2 = double, Tail = []
) 这种类型继承foo_validator<>
。foo_validator<>
并找到完全匹配的特化,即上面列表中的类型 2。 在“继承foo_validator
”方法中,没有任何反应,编译继续进行。 在static_assert
方法中,此类型继承std::true_type
,因此断言成功。 现在让我们看一个不应该工作的类型: SomeFunction<Foo<int, int>, std::pair<float, double>>
:
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>>
。foo_validator<std::pair<float, double>>
。 这与上面列表中的类型 2 或 3 不匹配,因此编译器尝试实例化基本模板声明(类型 1)。 在“ foo_validator
方法”中,这会失败,因为模板类型不完整(我们从未定义过它)。 在static_assert
方法中,基模板被实例化并继承std::false_type
,因此断言失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.