可变参数模板 - 不完整类型

发布于 2024-12-11 21:38:11 字数 646 浏览 0 评论 0原文

有这个代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凉宸 2024-12-18 21:38:11

我认为模板的定义是错误的,在这两种情况下你都会触发精确的递归。我本以为编译器会因编译器内部出现一些 stackoverflow 而死掉,但会产生不同的错误...

are_same 可变参数模板的实现可能是:

template <class... Args>                    // base (optional to declare the template)
struct are_same;

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = is_same<A,B>::value && are_same<A,Args...>::value;
};

template <class A, class B>                 // stop condition
struct are_same<A,B> {
    static const bool value = is_same<A,B>::value;
};

请注意,在 recursion 步骤,从参数列表中删除一个参数,以便要解决的新问题是原始问题的简化版本。这种类型的模板元编程与递归非常相关,并且适用相同的规则,为了能够使用递归,您需要确保每个递归步骤都让您更接近解决方案。在这种特殊情况下,给定 N 个可能相同的类型的列表,每个步骤都将问题简化为查找 N-1 个类型是否相同。

您也可以使用 are_same 问题的退化版本作为停止条件(替换前一个):

template <class A> 
struct are_same<A> {
   static const bool value = true;
};

这是退化,因为它确实没有意义询问单一类型是否*are_same*,但对于不同的元编程任务来说它可能是合适的。

不依赖于 is_same 的不同的潜在更有效的算法(我不确定编译器是否会避免上面的递归步骤中的模板实例化)可能是:

template <class... Args>
struct are_same;

template <class A, class... Args>
struct are_same<A,A,Args...> {              // recursion
    static const bool value = are_same<A,Args...>::value;
};

template <class A, class B, class... Args>
struct are_same<A,B,Args...> {              // cut, A and B are not the same
    static const bool value = false;
};

template <class A>
struct are_same<A> {                        // end of recursion
    static const bool value = true;
};

在这种情况下,编译器将当两种类型相同时,我们更喜欢使用递归而不是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:

template <class... Args>                    // base (optional to declare the template)
struct are_same;

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = is_same<A,B>::value && are_same<A,Args...>::value;
};

template <class A, class B>                 // stop condition
struct are_same<A,B> {
    static const bool value = is_same<A,B>::value;
};

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:

template <class A> 
struct are_same<A> {
   static const bool value = true;
};

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:

template <class... Args>
struct are_same;

template <class A, class... Args>
struct are_same<A,A,Args...> {              // recursion
    static const bool value = are_same<A,Args...>::value;
};

template <class A, class B, class... Args>
struct are_same<A,B,Args...> {              // cut, A and B are not the same
    static const bool value = false;
};

template <class A>
struct are_same<A> {                        // end of recursion
    static const bool value = true;
};

In this case, the compiler will prefer the recursion to the cut steps whenever the two types are the same, so we need not check is_same internally. At the same time, if the compiler goes into the cut step, we don't need to process the rest of the type list, as we already know the answer.

偏闹i 2024-12-18 21:38:11

我会这样做:

#include <type_traits>
#include <iostream> 

template <class... Args>
struct are_same
{
  static const bool value=true;
};

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value;
};

int main()
{
    std::cout<< std::boolalpha << are_same< int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl;
}

I would do it like this :

#include <type_traits>
#include <iostream> 

template <class... Args>
struct are_same
{
  static const bool value=true;
};

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value;
};

int main()
{
    std::cout<< std::boolalpha << are_same< int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl;
}
纵山崖 2024-12-18 21:38:11

最简单的实现可能是这样的:

template <typename... TList>
struct are_same { constexpr static bool value = false; };

template <typename T, typename... TList>
struct are_same<T, T, TList...> { 
    constexpr static bool value = are_same<T, TList...>::value; 
};

template <typename T>
struct are_same<T> { constexpr static bool value = true; };

或者,您可以将停止条件替换为

template <typename T>
struct are_same<T, T> { constexpr static bool value = true; };

但第一个更通用,因为 are_same::value == true。另一个问题是 are_same<>::value 应该等于什么。这会给你 false 但添加一个像这样的模板专业化并不是什么大问题。

template <>
struct are_same<> { constexpr static bool value = true; };

Probably simplest implementation could be like this:

template <typename... TList>
struct are_same { constexpr static bool value = false; };

template <typename T, typename... TList>
struct are_same<T, T, TList...> { 
    constexpr static bool value = are_same<T, TList...>::value; 
};

template <typename T>
struct are_same<T> { constexpr static bool value = true; };

Alternatively you can replace stop condition with

template <typename T>
struct are_same<T, T> { constexpr static bool value = true; };

But the first one is more general because are_same<type>::value == true. Another question is what should be are_same<>::value equal to. This gives you false but it is not a big deal to add one more template specialisation like this.

template <>
struct are_same<> { constexpr static bool value = true; };
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文