【问题标题】:Checking for a nested, templated class检查嵌套的模板类
【发布时间】:2014-06-09 10:05:30
【问题描述】:

我正在尝试构建一个特征来检查是否存在嵌套的模板类。这是我检查一个类O是否有一个嵌套类inner和模板参数T

template <typename O, typename T> struct has_inner {
    static const bool value = std::is_class<typename O::template inner<T> >::value;
};

但是,这不能正常工作。给定两个示例类dummyok

struct dummy {};
struct ok {
    template <typename T>
    struct inner {
    };
};

检查ok

std::cout << std::boolalpha << has_inner<ok, float>::value << std::endl;

会起作用,而检查dummy

std::cout << std::boolalpha << has_inner<dummy, int>::value << std::endl;

将无法在 clang 3.2 上编译并出现错误

error: 'inner' following the 'template' keyword does not refer to a template
    static const bool value = std::is_class<typename O::template inner<T> >::value;
                                                                 ^~~~~
note: in instantiation of template class 'has_inner<dummy, int>' requested here
    std::cout << std::boolalpha << has_inner<dummy, int>::value << std::endl;

编译器似乎在将模板化表达式传递给std::is_class 之前尝试实际形成该表达式。因此,我看到了两种解决方案:

  1. 告诉编译器延迟模板扩展,或者
  2. 完全使用不同的方法。

但是,我也不知道该怎么做,谁能帮忙?

【问题讨论】:

    标签: c++ templates c++11 typetraits


    【解决方案1】:

    问题

    您通常使用并依赖SFINAE 来实现这样的特征,这是您的实现没有利用的东西。

    如前所述,无论是否可能,编译器都会尝试实例化typename O::template inner&lt;T&gt;;如果不可能,编译器会在你的脸上抛出错误诊断。

    您需要做的是有条件地检查T 里面是否真的有一个template-class,如果没有就不用实例化它。


    解决方案 - SFINAE 救援!

    一个实现可能看起来像下面的sn-p,后面会有解释。

    namespace impl {
      template<class T, class... Args>
      struct has_inner {
        template<class U, typename = typename U::template inner<Args...>> // (A)
        static std::true_type  test (int);
    
        template<class U>
        static std::false_type test (...);                                // (B)
    
        using result_type = decltype (test<T> (0));                       // (C)
      };
    }
    
    template<class... Ts>
    using has_inner = typename impl::has_inner<Ts...>::result_type;
    

    注意:通过使用decltype(test&lt;T&gt;(0)),我们将获得 std::true_typestd::false_type,它们是处理 type-traits 的结果时的标准行为。


    SFINAE 的规则规定,如果一个函数模板在实例化时会产生一个无效的函数声明,就好像这个函数不存在,编译器会尝试寻找另一个匹配,而不是放弃。

    这就是在 (C) 处发生的情况,我们尝试调用 (A),但如果失败(即,template&lt;class U, typename ...&gt; 中的 yield 表达式无效,我们将最终调用 (B)。

    (B) 不如 (A) 的成功实例化那么好,但如果 (A) 不能实例化.. (B) 会做。

    【讨论】:

      【解决方案2】:

      您需要使用 trait 类和 SFINAE,如下所示:

      template<class A, typename B>
      struct has_inner
      {
      private:
          template<class T, typename U>
          static std::true_type has(typename T::template inner<U>*);
      
          template<class, typename>
          static std::false_type has(...);
      public:
          static constexpr auto value = decltype(has<A, B>(nullptr))::value;
      };
      

      现在您可以使用它并获得正确的结果:

      static_assert(has_inner<ok, float>::value, "ok does not have inner");    // OK
      static_assert(has_inner<dummy, float>::value, "dummy does not have inner"); // ERROR 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-04
        • 2018-11-08
        • 2018-11-26
        • 1970-01-01
        相关资源
        最近更新 更多