【问题标题】:Metaprogramming member checker doesn't work with function members returning a type with a base class元编程成员检查器不适用于返回具有基类的类型的函数成员
【发布时间】:2015-11-11 21:38:23
【问题描述】:

我已经实现了一个像这样的元编程成员检查器:

//Declare a metaprogramming test to check if a class has a member
//of a given signature and a certain name
#define DECL_hasMember(MEMBER)                                                  \
/* Check if T has member MEMBER M is a pointer to member of T type (T::*) */    \
template <typename T, typename M>                                               \
class hasMember_##MEMBER {                                                      \
    private:                                                                    \
        typedef char passed[1];                                                 \
        typedef char failed[2];                                                 \
                                                                                \
        template <typename U, U> struct reallyHas;                              \
                                                                                \
        template <typename C> static passed& test(reallyHas<M, &C::MEMBER>*);   \
        template <typename C> static failed& test(...);                         \
                                                                                \
        hasMember_##MEMBER()=delete;                                            \
    public:                                                                     \
        static bool const value = sizeof(test<T>(nullptr)) == sizeof(passed);   \
}

我已经在许多情况下对此进行了测试,并且检查器在大多数情况下都可以正常工作,

现在我正在使用奇怪的重复模板模式实现一个有限状态机,它有一个将状态与派生类的函数相关联的映射。我希望这个派生类有一个名为 buildFSM 的成员,创建所述地图。我想使用静态断言强制执行此操作,以获得更好的编译器错误。但是元编程检查器似乎无法检测到desc_t

(为了这个问题,我试图在一个更简单的场景中复制这种情况,但无法让它在不同的上下文中失败)

DECL_hasMember(buildFSM);

template<class Executor_T, typename State_T = uint32_t, typename ... Args>
class FSM
{
    public:
        typedef State_T state_t;
        typedef FSM<Executor_T, State_T, Args...> fsm_t;

    protected:
        /* returns the next state */
        typedef state_t (Executor_T::*handler_t)(Args...);
        /* holds all the states */
        struct desc_t : private std::map<state_t, handler_t> {
            friend fsm_t;
            void addState(const state_t&, handler_t);

            using std::map<state_t, handler_t>::size;
            using std::map<state_t, handler_t>::empty;
        };

    private:
        /* Implementation must implement buildFSM returning a desc_t that initializes this */
        static desc_t states;

        static_assert(hasMember_buildFSM<Executor_T, desc_t(Executor_T::*)()>::value,
            "Implementing class must provide desc_t buildFSM() function member.");

    /* [...] */
};

//Delegate the initialization of states to the derived class
template<class E, typename S, typename ... A>
decltype(FSM<E, S, A...>::states) FSM<E, S, A...>::states= std::move(E::buildFSM());

struct test : public FSM<test> {
    fsm_t::desc_t buildFSM() {
        return fsm_t::desc_t();
    }
};

正如我之前所说,静态断言失败,即它无法检测到test::buildFSM。问题出在desc_t,因为如果我将其更改为另一种类型,则测试通过就好了。如果我修改desc_t 使其不派生std::map,则测试也通过了。为什么会这样?在这种情况下,我能做些什么来完成这项工作吗?我知道另一种选择是将地图作为成员而不是基类,但我不明白为什么会发生这种情况。

我在 Visual Studio 2015 中。

【问题讨论】:

  • 我也在 Visual Studio 2015 中,这导致我的编译器崩溃。我不再感到惊讶了。
  • 这不会在 Clang 或 GCC 中编译,这不足为奇;在 FSM&lt;test&gt; 实例化时,test 是一个不完整的类型,但您的 static_assert 检查其成员,这当然会失败。

标签: c++ templates metaprogramming


【解决方案1】:

结帐:Member detector

下面是一些检测成员函数的代码:

#include <iostream>

// single argument and return type
#define DECL_hasMemberRetArg(MEMBER)                                          \
template<typename T, typename RESULT, typename ARG1>                          \
class Detect_RetArg_##MEMBER                                                  \
{                                                                             \
    template <typename U, RESULT (U::*)(ARG1)> struct Check;                  \
    template <typename U> static char func(Check<U, &U::MEMBER> *);           \
    template <typename U> static int func(...);                               \
  public:                                                                     \
    typedef Detect_RetArg_##MEMBER type;                                      \
    enum { value = sizeof(func<T>(0)) == sizeof(char) };                      \
}

// two arguments and return type
#define DECL_hasMemberRetArgArg(MEMBER)                                       \
template<typename T, typename RESULT, typename ARG1, typename ARG2>           \
class Detect_RetArgArg_##MEMBER                                               \
{                                                                             \
    template <typename U, RESULT (U::*)(ARG1, ARG2)> struct Check;            \
    template <typename U> static char func(Check<U, &U::MEMBER> *);           \
    template <typename U> static int func(...);                               \
  public:                                                                     \
    typedef Detect_RetArgArg_##MEMBER type;                                   \
    enum { value = sizeof(func<T>(0)) == sizeof(char) };                      \
}

class a_t
{
  char get(int);
  char put(int,long);
};

struct b_t
{
  char get(int);
  char put(int,long);
};

struct c_t : public b_t
{
};

DECL_hasMemberRetArg(get);
DECL_hasMemberRetArgArg(put);

int main()
{
  std::cout << Detect_RetArg_get<a_t, char, int>::value << "\n";          // 0
  std::cout << Detect_RetArgArg_put<a_t, char, int, long>::value << "\n"; // 0
  std::cout << Detect_RetArg_get<b_t, char, int>::value << "\n";          // 1
  std::cout << Detect_RetArgArg_put<b_t, char, int, long>::value << "\n"; // 1
  std::cout << Detect_RetArg_get<c_t, char, int>::value << "\n";          // 0
  std::cout << Detect_RetArgArg_put<c_t, char, int, long>::value << "\n"; // 0
  return 0;
}

模板看不到基类成员。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多