7

有这个代码:

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<A,C...>::value我会调用递归调用,最后会简单地扩展为Are_Same<A,B>. 显然事实并非如此。任何人都知道我在哪里犯错?

4

3 回答 3

8

我认为模板的定义是错误的,在这两种情况下你都会触发精确递归。我原以为编译器会在编译器内部出现一些 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;
};

在这种情况下,只要两种类型相同,编译器就会优先选择recursion步骤cut,因此我们不需要is_same内部检查。同时,如果编译器进入该cut步骤,我们不需要处理类型列表的其余部分,因为我们已经知道了答案。

于 2011-10-25T08:20:42.917 回答
3

我会这样做:

#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;
}
于 2011-10-25T08:32:50.103 回答
0

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

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<type>::value == true. 另一个问题是应该are_same<>::value等于什么。这给了你false,但添加一个像这样的模板专业化并不是什么大不了的事。

template <>
struct are_same<> { constexpr static bool value = true; };
于 2013-07-31T08:20:07.460 回答