c++ - 元编程成员检查器不适用于返回具有基类的类型的函数成员

标签 c++ templates metaprogramming

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

//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 的成员,用于创建所述 map 。我想使用静态断言来强制执行此操作,以获得更好的编译器错误。但是元编程检查器似乎无法检测到 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,测试也会通过。为什么会这样?在这种情况下,我能做些什么来完成这项工作吗?我知道另一种方法是将 map 作为成员而不是基类,但我不明白为什么会这样。

我在 Visual Studio 2015 中。

最佳答案

结帐: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;
}

模板看不到基类成员。

关于c++ - 元编程成员检查器不适用于返回具有基类的类型的函数成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33660319/

相关文章:

c++ - 在 C++ 中将数组编码为 jpeg 图像

c++ - 非依赖名称的重载解析何时发生,在定义上下文或实例化点?

c# - 在运行时编译和使用类

c++ - 如何为子类定义通用模板化创建函数

c++ - 为什么当一个模板类继承另一个模板类时,需要重新指定typedefs和函数调用限定?

c++ - 通过参数启用时 std::enabled_if 如何工作

C++结构的自动比较器

c++ - OpenCV - OpenCV Mat 等效于 boost 矩阵 array_type

c++ - 引用未初始化的内存而不访问它是否合法?

c++ - 跨内核线程迁移后是否可以强制重新加载 thread_local 变量?