令人困惑的部分模板专业化

时间:2018-01-14 08:16:38

标签: c++ templates boost typetraits

我看到了这段代码,这让我很困惑:

#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>

template<class TT, typename Enable = void> struct UU { BOOST_STATIC_ASSERT_MSG(sizeof(TT) == 0, "undefined UU"); };

template<class TT>
struct UU<
        TT,
        typename boost::enable_if_c<
                !boost::is_same<
                        TT,
                        typename boost::remove_cv<
                                typename boost::decay<TT>::type
                            >::type
                    >::value
                || boost::is_pointer<TT>::value
            >::type
    >
    : UU<
            typename boost::remove_cv<
                typename boost::decay<
                    typename boost::remove_pointer<TT>::type
                >::type
            >::type
        >
{};

我知道我只应该问一个问题,但我不确定如何只用一个问题表达我的困惑,所以我提前道歉。

我已经阅读了SFINAE,但是enable_if_c的模板参数令人困惑。这是否意味着如果TT与衰减的TT不同或TT是指针,那么部分模板专业化是否存在?

其次,结构继承自身意味着什么?在这种情况下,UU是否继承自UU(本身)?这是某种递归模板吗?

(代码编译时没有错误。)

3 个答案:

答案 0 :(得分:2)

  

这是否意味着如果TT与衰减的TT不同或TT是指针,那么部分模板专业化是否存在?

完全。否则,替换失败,主模板用于传入的类型参数TT

  

其次,结构继承自身意味着什么?在这种情况下,UU是否继承自UU(本身)?这是某种递归模板吗?

它不会从自身继承,它继承自类模板的另一个实例。它不是真正的递归,因为通过将另一个经过修改的类型传递给它来创建其他实例化。虽然如果你认为模板是对类型进行操作的元函数,那么这确实是一个递归调用。与你在函数式编程中看到的非常相似。

这个想法是将复合类型减少为它所组成的类型。所以引用类型的引用,数组元素类型的数组和指向者类型的指针。继承允许该过程继续,直到我们手上没有复合类型。

最终,主模板检查缩减类型的正确性(在这种情况下,大小非零)。

答案 1 :(得分:0)

它继承自UU但实例化是不同的(例如,如果传递的类型是int * const *,即使在第一级指针和cv被删除后它仍然是一个指针)。但是,它确实没有传递void **(因为void参数最终将使用静态断言触发主窗体)。

答案 2 :(得分:0)

我想我现在明白了。这是一个示例模拟:

#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <typeinfo>
#include <iostream>

template<class TT, typename Enable = void> struct UU { BOOST_STATIC_ASSERT_MSG(sizeof(TT) == 0, "undefined UU"); };

template<class TT>
struct UU<
        TT,
        typename boost::enable_if_c<
                !boost::is_same<
                        TT,
                        typename boost::remove_cv<
                                typename boost::decay<TT>::type
                            >::type
                    >::value
                || boost::is_pointer<TT>::value
            >::type
    >
    : UU<
            typename boost::remove_cv<
                typename boost::decay<
                    typename boost::remove_pointer<TT>::type
                >::type
            >::type
        >
{
    UU()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct dummy
{
    dummy()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl; 
    }
};

template<>
struct UU<dummy>
{
    UU()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

int main()
{
    typedef dummy**& mytype;
    std::cout << typeid(typename boost::remove_cv<typename boost::decay<mytype>::type>::type).name() << std::endl;
    std::cout << boost::is_pointer<mytype>::value << std::endl;
    std::cout << boost::is_same<mytype, typename boost::remove_cv<typename boost::decay<mytype>::type>::type>::value << std::endl;

    UU<mytype> uu;
    return 0;
}

运行时:

me@ub16:~/tmp/traits$ g++ -I~/me/bin/boost_1_60_0 c.cpp && ./a.out
PP5dummy
0
0
UU<dummy>::UU()
UU<TT, typename boost::enable_if_c<((! boost::is_same<TT, typename boost::remove_cv<typename boost::decay<T>::type>::type>::value) || boost::is_pointer<T>::value)>::type>::UU() [with TT = dummy*; typename boost::enable_if_c<((! boost::is_same<TT, typename boost::remove_cv<typename boost::decay<T>::type>::type>::value) || boost::is_pointer<T>::value)>::type = void]
UU<TT, typename boost::enable_if_c<((! boost::is_same<TT, typename boost::remove_cv<typename boost::decay<T>::type>::type>::value) || boost::is_pointer<T>::value)>::type>::UU() [with TT = dummy**; typename boost::enable_if_c<((! boost::is_same<TT, typename boost::remove_cv<typename boost::decay<T>::type>::type>::value) || boost::is_pointer<T>::value)>::type = void]
UU<TT, typename boost::enable_if_c<((! boost::is_same<TT, typename boost::remove_cv<typename boost::decay<T>::type>::type>::value) || boost::is_pointer<T>::value)>::type>::UU() [with TT = dummy**&; typename boost::enable_if_c<((! boost::is_same<TT, typename boost::remove_cv<typename boost::decay<T>::type>::type>::value) || boost::is_pointer<T>::value)>::type = void]
me@ub16:~/tmp/traits$ 

实例化UU<dummy**&>时,编译器会尝试创建/定义struct UU<dummy**>。然后它尝试创建struct UU<dummy*>。最后,它会创建struct UU<dummy>

如果未定义部分模板特化,struct UU<dummy>,则主模板的静态断言将失败:

me@ub16:~/tmp/traits$ g++ -I~/me/bin/boost_1_60_0 c.cpp && ./a.out
In file included from c.cpp:1:0:
c.cpp: In instantiation of ‘struct UU<dummy, void>’:
c.cpp:10:8:   recursively required from ‘struct UU<dummy**, void>’
c.cpp:10:8:   required from ‘struct UU<dummy**&>’
c.cpp:62:13:   required from here
c.cpp:7:56: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’
 template<class TT, typename Enable = void> struct UU { BOOST_STATIC_ASSERT_MSG(sizeof(TT) == 0, "undefined UU"); };

本质上,代码的作者希望其他开发人员使用他/她的代码为每个要使用的TT定义部分模板特化template<> struct UU<TT>