如何显式地将某些模板化输入作为参数?
How to explicitly take in certain templated inputs as arguments?
我有Foo<a, b>
和Foo<c, d>
,其中Foo
接受 2 个模板化参数。如果我有一个带有类SomeFunction
的可变参数模板,它接受这些Foo
输入,如下所示:
template <typename... Ts>
class SomeFunction< /*some input*/ >
我该怎么做才能确保SomeFunction
只接受Foo
模板,而不是像Blah<a,b>
这样的其他模板?
你可以让你的类型私下继承另一个类型,除非类型参数正确,否则无法实例化。 将模板类型保留为未定义,然后部分专用于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
可以是任何类型)之外的任何类型参数,则任何专用化都不会匹配,编译器将尝试实例化非专用模板。 由于未定义,这将导致编译错误。
本声明:
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
,因此断言失败。
- 将输入参数作为右值引用传递?
- 是否可以在命令行中将输入参数传递给可执行文件
- C++基于输入参数的动态代码生成
- 我想知道为什么"std::unique_ptr<int> foo(新 int)"是合法的,因为"std::<int>unique_ptr"要求输入参数类型应该是"int"?
- 如何使用输入参数作为文件的传递?
- 在函数中使用运算符重载,在 c++ 中使用 const 类型输入参数
- 提供变量作为 MATLAB 系统命令的输入参数,以便C++可执行文件
- 函数的函数无法识别输入参数
- 当迭代器(输入参数)通常不是constexpr时,constexpr算法真的有用吗
- 如何将一个使用参数包和typename的类作为函数(c++)的输入参数
- CvMat:输入参数的大小不匹配
- 在什么情况下,使用'const T*'输入参数比'const T&'更可取?
- std::具有两个输入参数的矢量构造函数
- GoogleMock:如何根据另一个输入参数设置ArgReferee?
- 模板化函数以从输入参数推断返回类型 stl-container
- GoogleMock:如何验证输入参数的调用次数?
- 当我将 char 数组发送到输入参数为字符串的函数时会发生什么?
- 应该接受不同输入参数的纯虚函数 - 应该如何实现
- C++主函数的输入参数
- STD :: Atomic_fetch为什么将指针作为其输入参数