【问题标题】:Compile-time check if iterator's parent class public member exists编译时检查迭代器的父类公共成员是否存在
【发布时间】:2016-04-08 15:04:36
【问题描述】:

我有一堂课:

class A
{
// ...
public:
    std::string s;
// ...
}

还有一个功能:

void some_process(RandomIt first, RandomIt last)
{
    static_assert(/* some check if *RandomIt has member with name `s` */,
                  "Iterator must point to an object with member `s`");

    // further process using RandomIt and using *RandomIt.s
}

如何在 C++ 到 C++17 的情况下实现此检查?

【问题讨论】:

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


    【解决方案1】:

    #include <type_traits>
    #include <utility>
    
    template <typename T, typename = void>
    struct has_s : std::false_type {};
    
    template <typename T>
    struct has_s<T, decltype(void(std::declval<T>()->s))> : std::true_type {};
    
    template <typename RandomIt>
    void some_process(RandomIt first, RandomIt last)
    {
        static_assert(has_s<RandomIt>{},
                      "Iterator must point to an object with member `s`");
    }
    

    DEMO

    :

    #include <type_traits>
    #include <utility>
    
    template <typename T>
    using has_s_t = decltype(std::declval<T>()->s);
    
    template <typename RandomIt>
    void some_process(RandomIt first, RandomIt last)
    {
        static_assert(std::is_detected_v<has_s_t, RandomIt>,
                      "Iterator must point to an object with member `s`");
    }
    

    DEMO 2

    【讨论】:

      【解决方案2】:

      另一个潜在的 C++1z 选项是概念。这是一个简单的概念示例,它本身可能没有用,但可以根据您的情况使用该想法。

      template<typename T>
      concept bool PointeeHasSMember = requires(T t) 
      {
          t->s; // require t->s to be a valid expression
      };
      
      struct with_s 
      {
          int s;
      };
      
      struct no_s {};
      
      void some_process(PointeeHasSMember first, PointeeHasSMember last) {}
      
      int main()
      {
          with_s* with;
          no_s* without;
      
          some_process(with, with); // compiles
          some_process(without, without); // doesn't compile
      }
      

      latest GCC 下,第二次调用会产生与相关行concept 'PointeeHasSMember&lt;no_s*&gt;' was not satisfied' was not satisfied 相关的错误。

      使用概念的优点是实现简单,即使与检测习语相比也是如此,并且概念成为功能模板的一部分。您可以灵活地嵌套需求、执行动态需求和重载概念。您的函数声明还清楚地说明了它的要求,而不是将其延迟到静态断言。

      【讨论】:

        猜你喜欢
        • 2011-09-23
        • 2020-05-25
        • 2013-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多