【问题标题】:Confusing partial template specialization令人困惑的部分模板专业化
【发布时间】:2018-01-14 08:16:38
【问题描述】:

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

#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(本身)继承的吗?这是某种递归模板吗?

(代码编译没有错误。)

【问题讨论】:

  • enable_if_c 条件为真时将选择专业化。 UU 不继承自自身,它继承自同一模板的不同特化。
  • 如果代码实际使用了名称UUTT,那才是真正的问题。如果您只是为了在Stack Overflow 上询问而删除了真实姓名,那是……不可原谅的。代码是供人阅读的。去掉语义线索后代码难以理解,不要感到惊讶(询问逆向工程师)

标签: c++ templates boost typetraits


【解决方案1】:

是否意味着如果TT与衰减后的TT不同,或者如果TT是指针,则存在部分模板特化?

没错。否则会出现替换失败,并且主模板将用于您传入的类型参数 TT

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

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

这个想法是将复合类型简化为它所组成的类型。所以引用类型的引用,数组元素类型的数组和指针类型的指针。继承允许该过程继续进行,直到我们手头没有复合类型为止。

最终,主模板检查缩减类型的正确性(在本例中,大小不为零)。

【讨论】:

  • "主模板检查缩减类型的正确性(在这种情况下,具有非零大小)" - 什么是不正确的 类型? C++ 中的 sizeof 不总是 >0 吗?
  • @RustyX - 总是在标准 C++ 中。但是扩展确实存在,一些病态的情况可以用sizeof 0 创建类。就像sehe 指出的那样,OP 为模板及其参数选择了一些非常糟糕的名称。我不知道像这样的实际模板可能在哪里使用,但它旨在捕捉那些令人讨厌的惊喜并不是不可想象的。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    #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&lt;dummy**&amp;&gt; 被实例化时,编译器会尝试创建/定义struct UU&lt;dummy**&gt;。然后它尝试创建struct UU&lt;dummy*&gt;。最后,它创建struct UU&lt;dummy&gt;

    当部分模板特化struct UU&lt;dummy&gt;未定义时,主模板的静态断言失败:

    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&lt;&gt; struct UU&lt;TT&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-12
      • 2019-02-06
      • 1970-01-01
      相关资源
      最近更新 更多