4

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

下面的 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 特性重写它……这里应该用什么来代替?

4

2 回答 2

6

使用 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::*)()"

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

于 2013-01-18T17:16:42.110 回答
0

是的,在 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)
    );
};

然后在您的班级中,您可以只使用 astatic_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>())>
{
    ...
};
于 2014-07-01T22:40:06.227 回答