【问题标题】:Member Function checking: Implement compilation-time checkings with C++11 features成员函数检查:使用 C++11 特性实现编译时检查
【发布时间】:2013-01-18 17:05:31
【问题描述】:

我已经读到 C++11 有足够的静态检查(编译时间),以便实现 C++11(已删除)的概念检查的很大一部分。 (我在最近的一个关于删除概念的问题的 cmets 中读到了这篇文章...... - 这个问题很快就被关闭了,因为没有建设性)。

下面的 C++03 代码仅检查类中是否存在成员函数(我的模板类希望在该类上工作)。以下是搜索的 4 个成员函数,我总是使用相同的模式:

  • 一个typedef来定义函数原型的typedef
  • 如果类型名 TExtension 没有定义这样的成员函数,或者如果它有不同的原型,则调用 static_cast 会中断编译

代码如下:

template <typename TExtension>
class
{
...
    void checkTemplateConcept()
    {
        typedef unsigned long (TExtension::*memberfunctionRequestedId)();
        static_cast<memberfunctionRequestedId>(&TExtension::getRequestId);

        typedef eDirection (TExtension::*memberfunctionDirection)();
        static_cast<memberfunctionDirection>(&TExtension::getDirection);

        typedef eDriveWay (TExtension::*memberfunctionDriveWay)();
        static_cast<memberfunctionDriveWay>(&TExtension::getDriveWay);

        typedef unsigned long (TExtension::*memberfunctionCycleId)();
        static_cast<memberfunctionCycleId>(&TExtension::getCycleId);
    }
}

这是我代码的某些部分,但它完全基于 C++03。我很乐意用那些新的 C++11 功能重写它......这里应该使用什么来代替?

【问题讨论】:

    标签: c++ c++11 c++-concepts


    【解决方案1】:

    使用 C++11,您可以让编译器打印带有 static_assert 的良好错误消息:

    typedef unsigned long (TExtension::*required_type)();
    typedef decltype(&TExtension::getRequestId) actual_type;
    
    static_assert(std::is_same<required_type, actual_type>::value,
         "The type of getRequestId must be unsigned long (C::*)()");
    

    现在如果成员函数的类型不匹配,编译器将打印这条有用的消息:

    "The type of getRequestId must be unsigned long (C::*)()"
    

    如果你愿意,你可以让它更具描述性。 :-)

    【讨论】:

      【解决方案2】:

      是的,在 C++11 中,SFINAE 被扩展为表达式,因此您可以定义像 is_t_extension 这样的特征来检测成员函数的存在,如下所示:

      template<class... T>
      struct holder
      {
          typedef void type;
      };
      
      template<class T, class=void>
      struct is_t_extension
      : std::false_type
      {};
      
      template<class T, class=void>
      struct is_t_extension<T, typename holder<
          decltype(std::declval<T>().getRequestId),
          decltype(std::declval<T>().getDirection),
          decltype(std::declval<T>().getDriveWay),
          decltype(std::declval<T>().getCycleId)
      >::type>
      : std::true_type
      {};
      

      现在这只是检查他们的存在。通过一些工作,您可以扩展上述内容以检测有效签名,或者您可以使用Tick 库来编写特征,这看起来更清晰:

      TICK_TRAIT(is_t_extenstion)
      {
          template<class T>
          auto requires_(T&& x) -> TICK_VALID(
              returns<unsigned long>(x.getRequestId),
              returns<eDirection>(x.getDirection),
              returns<eDriveWay>(x.getDriveWay),
              returns<unsigned long>(x.getCycleId)
          );
      };
      

      那么在你的课堂上你可以使用static_assert 来报告错误:

      template <typename TExtension>
      class foo
      {
          static_assert(is_t_extension<TExtension>(), "Not a TExtension");
      };
      

      或者如果你想允许专业化,你可以使用TICK_CLASS_REQUIRES

      template <typename TExtension, class=void>
      class foo;
      
      template <typename TExtension>
      class foo<TExtension, TICK_CLASS_REQUIRES(is_t_extension<TExtension>())>
      {
          ...
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-29
        • 2011-01-06
        • 2012-04-30
        • 2013-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多