检查参数包是否包含类型
我想知道 C++0x 是否提供任何内置功能来检查可变参数模板的参数包是否包含特定类型。今天,如果您使用 boost:::mpl::vector 作为可变参数模板的替代品,则可以使用 boost:::mpl::contains 来完成此任务。然而,它具有严重的编译时间开销。我想,C++0x 对 std::is_same 具有编译器级支持。所以我在想编译器是否也支持像下面这样的泛化。
template <typename... Args, typename What>
struct is_present
{
enum { value = (What in Args...)? 1 : 0 };
};
I was wondering if C++0x provides any built-in capabilities to check if a parameter pack of a variadic template contains a specific type. Today, boost:::mpl::contains can be used to accomplish this if you are using boost::mpl::vector as a substitute for variadic templates proper. However, it has serious compilation-time overhead. I suppose, C++0x has compiler-level support for std::is_same. So I was thinking if a generalization like below is also supported in the compiler.
template <typename... Args, typename What>
struct is_present
{
enum { value = (What in Args...)? 1 : 0 };
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
幸运的是,C++ 标准已经发展。使用 C++1z 又名 C++17,您终于可以轻松地迭代参数包。因此,答案的代码(几乎)很简单,正如问题中所建议的:
看起来怪异的
(std::is_same_v|| ...)
由编译器内部为(std::is_same_v|| std::is_same_v|| ...)
,这正是,你想要什么。它甚至可以正确地生成带有空Args
参数包的false
。甚至可以在函数或方法中内联执行整个检查 - 不再需要辅助结构:
注意:这取自 另一个问题,已标记为此问题的重复项。由于这是本主题的“规范”问题,因此我在此处添加了重要信息。
Fortunately, the C++ standard has evolved. With C++1z aka C++17, you can finally iterate easily over parameter packs. So the code for the answer is (almost) as simple, as suggested in the question:
The weird-looking
(std::is_same_v<What, Args> || ...)
is expanded by the compiler internally to(std::is_same_v<What, Args[0]> || std::is_same_v<What, Args[1]> || ...)
, which is exactly, what you want. It even correctly yieldsfalse
with an emptyArgs
parameter pack.It is even possible to do the whole check inline in a function or method - no helper structs are required anymore:
Note: This has been taken from another question, that was marked as a duplicate of this question. As this is the "canonical" question for this topic, I added that important information here.
不,您必须使用可变参数模板的(部分)专业化来进行如下编译时计算:
可变参数模板只有另一种内在操作,那就是 sizeof 运算符的特殊形式,它计算参数列表的长度例如:
您从哪里得到“它具有严重的编译时间开销”和 boost mpl 的信息?我希望你不只是在这里做出假设。 Boost mpl 使用惰性模板实例化等技术来尝试减少编译时间,而不是像天真的模板元编程那样爆炸。
No, you have to use (partial) specialization with variadic templates to do compile-time computations like this:
There is only one other intrinsic operation for variadic templates and that is the special form of the sizeof operator which computes the length of the parameter list e.g.:
Where are you getting "it has serious compilation-time overhead" with boost mpl from? I hope you are not just making assumptions here. Boost mpl uses techniques such as lazy template instantiation to try and reduce compile-times instead of exploding like naive template meta-programming does.
如果您想避免手动类型递归,在我看来,std::common_type 是 STL 中唯一的实用程序,它是可变参数模板,因此也是唯一可能封装递归的实用程序。
解决方案 1
std::common_type
查找一组类型中派生最少的类型。如果我们识别具有类型的数字,特别是具有较少派生类型的高数字,它会找到集合中的最大数字。然后,我们必须将与键类型的相等性映射到派生级别。解决方案 2
我们可以对
common_type
进行更多修改。标准说并准确描述了其中的内容:递归部分特化情况、应用二元运算符的情况和终端情况。本质上,它是一个通用的
fold
函数,您可以添加任何您喜欢的二进制运算。这里我使用加法,因为它比 OR 提供更多信息。请注意,is_same
返回一个integral_constant
。If you want to avoid manual type recursion,
std::common_type
appears to me to be the only utility in the STL which is a variadic template, and hence the only one which could potentially encapsulate recursion.Solution 1
std::common_type
finds the least-derived type in a set of types. If we identify numbers with types, specifically high numbers with less-derived types, it finds the greatest number in a set. Then, we have to map equality to the key type onto a level of derivation.Solution 2
We can hack
common_type
a little more. The standard saysand describes exactly what is inside it: a recursive partial specialization case, a case which applies a binary operator, and a terminal case. Essentially, it's a generic
fold
function, and you can add whatever binary operation you please. Here I used addition because it's more informative than OR. Note thatis_same
returns anintegral_constant
.从 C++17 开始,您可以继承
std::disjunction
使用std::is_same...
的正常包扩展,在所有std::is_same
。您的is_present
类型特征将有一个static constexpr bool value
成员变量来保存结果。这与||
上的折叠表达式不同,因为如果找到匹配项,它会短路其余is_same<>::value
的实例化。您可以在下面的 C++11/14 实现中看到它是如何工作的。使用 C++11 或 C++14,您可以使用 析取 "nofollow noreferrer">
std::conditional
并在定义is_present
时使用该类型特征而不是std::disjunction
: C++14 您还可以创建辅助变量模板:
Since C++17, you can inherit from
std::disjunction
with a normal pack expansion ofstd::is_same<What, Args>...
which performs a logicalOR
between all thestd::is_same
s. Youris_present
type trait will have astatic constexpr bool value
member variable holding the result. This is different from a fold expression over||
since it's short-circuiting the instantiation of the rest of theis_same<>::value
s if a match is found. You can see how that works in the C++11/14 implementation below.Using C++11 or C++14, you can define your own
disjunction
usingstd::conditional
and use that type trait instead ofstd::disjunction
when definingis_present
:Since C++14 you can also create a helper variable template: