可变参数模板 - 不完整类型
有这个代码:
template<class ...Args>
struct Are_Same
{
enum {value = Are_Same<Args...>::value};
};
template<class A,class... C>
struct Are_Same<A,C...>
{
enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE
};
template<class A,class B>
struct Are_Same<A,B>
{
enum {value = std::is_same<A,B>::value};
};
我从 gcc 4.6.1 收到错误:
错误:使用的类型“Are_Same”不完整 嵌套名称说明符。
我认为通过执行 Are_Same::value
我将调用递归调用,最后将简单地扩展为 Are_Same
>。显然事实并非如此。谁知道我在哪里犯了错误?
Having this code:
template<class ...Args>
struct Are_Same
{
enum {value = Are_Same<Args...>::value};
};
template<class A,class... C>
struct Are_Same<A,C...>
{
enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE
};
template<class A,class B>
struct Are_Same<A,B>
{
enum {value = std::is_same<A,B>::value};
};
I'm getting error from gcc 4.6.1:
error: incomplete type 'Are_Same' used in
nested name specifier.
I thought that by doing Are_Same<A,C...>::value
I will invoke recursive call which at the end will simply expand to Are_Same<A,B>
. Obviously it's not the case. Anyone knows where am I making mistake?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为模板的定义是错误的,在这两种情况下你都会触发精确的递归。我本以为编译器会因编译器内部出现一些 stackoverflow 而死掉,但会产生不同的错误...
are_same
可变参数模板的实现可能是:请注意,在
recursion 步骤,从参数列表中删除一个参数,以便要解决的新问题是原始问题的简化版本。这种类型的模板元编程与递归非常相关,并且适用相同的规则,为了能够使用递归,您需要确保每个递归步骤都让您更接近解决方案。在这种特殊情况下,给定 N 个可能相同的类型的列表,每个步骤都将问题简化为查找 N-1 个类型是否相同。
您也可以使用
are_same
问题的退化版本作为停止条件(替换前一个):这是退化,因为它确实没有意义询问单一类型是否*are_same*,但对于不同的元编程任务来说它可能是合适的。
不依赖于 is_same 的不同的潜在更有效的算法(我不确定编译器是否会避免上面的递归步骤中的模板实例化)可能是:
在这种情况下,编译器将当两种类型相同时,我们更喜欢使用
递归
而不是cut
步骤,因此我们不需要在内部检查is_same
。同时,如果编译器进入cut
步骤,我们不需要处理类型列表的其余部分,因为我们已经知道答案。I think that the definitions of the templates are wrong, in both cases you are triggering exact recursion. I would have expected the compiler to die with some stackoverflow inside the compiler but a different error is produced...
An implementation of the
are_same
variadic template could be:Note that in the
recursion
step, one argument is dropped from the list of arguments, so that the new problem to resolve is a reduced version of the original. This type of template metaprogramming is quite related to recursion, and the same rules apply, to be able to use recursion you need to ensure that each recursive step gets you closer to a solution. In this particular case, given a list of N potentially same types, each step reduces the problem to finding whether N-1 types are the same.You can use alternatively, as stop condition (replacing the former one) a degenerate version of the
are_same
problem:Which is degenerate in the sense that it does not really make sense asking whether a single type *are_same*, but for different metaprogramming tasks it could be appropriate.
A different potentially more efficient algorithm (I am not sure whether the compiler will avoid the instantiation of the template in the recursion step above) that does not depend on
is_same
could be:In this case, the compiler will prefer the
recursion
to thecut
steps whenever the two types are the same, so we need not checkis_same
internally. At the same time, if the compiler goes into thecut
step, we don't need to process the rest of the type list, as we already know the answer.我会这样做:
I would do it like this :
最简单的实现可能是这样的:
或者,您可以将停止条件替换为
但第一个更通用,因为
are_same::value == true
。另一个问题是are_same<>::value
应该等于什么。这会给你false
但添加一个像这样的模板专业化并不是什么大问题。Probably simplest implementation could be like this:
Alternatively you can replace stop condition with
But the first one is more general because
are_same<type>::value == true
. Another question is what should beare_same<>::value
equal to. This gives youfalse
but it is not a big deal to add one more template specialisation like this.