可变参数模板的部分特化需要第一个非可变参数模板参数

时间:2013-08-11 14:25:53

标签: c++ c++11 variadic-templates partial-specialization

以下代码

#include <iostream>
#include <utility>

template<typename F, typename... T>
struct Wrapper{ };

template<typename T>
struct is_wrapper : std::false_type {};

template<typename... T>
struct is_wrapper<Wrapper<T...>> : std::true_type {};

//template<typename F, typename... T>
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {};

int main()
{
    Wrapper<int, double> w;

    std::cout << is_wrapper<decltype(w)>::value << std::endl;
}

打印0.但是,如果取消注释中间的两行,则打印1。

为什么不一直打印1?第二部分专业化是否也应该涵盖显然仅由第三(评论)部分专业化所涵盖的案例?

3 个答案:

答案 0 :(得分:1)

代码应该与部分特化完全匹配;该标准从未真正禁止这一点,但编译器确实需要一段时间才能正确实现可变参数模板及其演绎。 GCC自4.9.0以来一致,而Clang从3.6开始。 Clang的相关错误报告是#22191(我找不到GCC的。)

答案 1 :(得分:0)

通常,当我编写专门的模板时,我首先使用前向声明,并声明这些案例属于特殊化。在你的情况下,我知道你正在尝试编写一个没有空案例的可变参数模板(也就是说,一个至少有一种类型的可变参数模板)。

您的代码让我感到惊讶,因为我认为您是正确的,您的特征的完全可变特化与洞案例匹配......首先,我尝试使用特征类的前向声明,并且仅定义完全可变的专业化(因此,如果特征的参数不是Wrapper实例,则编译失败)。而这正是发生的事情,让我再次失望:

#include <iostream>
#include <utility>

template<typename F , typename... T>
struct Wrapper {};

template<typename T>
struct is_wrapper;

//template<typename T>
//struct is_wrapper : std::false_type {};

template<typename... T>
struct is_wrapper<Wrapper<T...>> : std::true_type {};

//template<typename F, typename... T>
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {};

using my_wrapper_type = Wrapper<int,double>;

int main()
{   
    std::cout << std::boolalpha  << is_wrapper<my_wrapper_type>::value << std::endl;
}//"Invalid use of incomplete type" ^^^^^^^^^^^^^^^^^^^^^^^^^^^

最后,我尝试了Wrapper类中的前向声明方法。令人惊讶的是,它有效:

#include <iostream>
#include <utility>

template<typename... T>
struct Wrapper;

template<typename F, typename... T>
struct Wrapper<F,T...>{ };


template<typename T>
struct is_wrapper : std::false_type {};

template<typename... T>
struct is_wrapper<Wrapper<T...>> : std::true_type {};

//template<typename F, typename... T>
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {};


using my_wrapper_type = Wrapper<int,double>;

int main()
{
    std::cout << std::boolalpha  << is_wrapper<my_wrapper_type>::value << std::endl;
}

打印:

  

Here是在ideone上运行的代码。

此致,我不明白为什么你的代码失败并且我的工作正常。 它是一个编译器错误,还是我们缺少的东西?我不知道。

答案 2 :(得分:0)

如果我理解你的问题,它只是一个专业化的优先事项,

is_wrapper<decltype(w)>

可以通过2个模板进行专业化:

template<typename T> // exact specialization
template<typename... T> // variadic specialization with one parameter 

在这种情况下,编译器优先选择精确的特化,因此模板永远不会在你的情况下实例化。