C ++ function local SFINAE

I have an error reporting system where unconfigured errors are ignored (configuration only means that there is a typedef for this error). Therefore, in those places where something is reported, it should become NOP if there is no typedef.

The problem is that I want to generate the SFINAE expression locally in order to be able to write something like (this is a work in progress, please ignore the naming, etc.):

Oh. And sorry. It must be compatible with C ++ 03/98. Stupid built-in compilers ...

// Error.h
template<uint32_t ID>
struct Error {  enum { value = ID };  };

enum { IGNORE_UNKNOWN = 1, DISALLOW_UNKNOWN = 2 };

// TheConfig.h
namespace config {
struct TheConfig {
    typedef Error<1> Error1;
    typedef Error<2> Error2;
    enum { MISSING_ERROR_POLICY = IGNORE_UNKNOWN };
};
}

// ErrorReport.h
template<typename T>
struct ReportEvent {
    inline void operator()() {
        T event;
        std::cout << "Called with error event" << event.value << std::endl;
    }
};

struct IgnoreEvent {
    inline void operator()() {
        std::cout << "Event ignored" << std::endl;
    }
};

// The magic macro defining a magic SFINAE 
#define REPORT_ERROR(event_name) \
    ....


// Usage
int f() {
    REPORT_ERROR(Error1);  // Reports the error
    REPORT_ERROR(Error5);  // Is a NOP as it is not configured
}

My current implementation, unfortunately, gives me (in visual studio) C2951: "type declarations are allowed only in the global namespace, or in the class." But going to the sub dummy class gives C2892: "The local class should not have member templates."

#define REPORT_ERROR(event_name) \
    { \
        template<typename T> struct void_type { \
            typedef void type; \
            enum { exists = false }; \
        }; \
        template<typename T, typename = void> \
        struct type_if_exists_##event_name : void_type<void> {}; \
        template<typename T> \
        struct type_if_exists_##event_name<T, typename void_type<typename T::event_name>::type>  \
        { \
            typedef typename T::event_name type; \
            enum { exists = true }; \
        }; \
    static_assert(config::TheConfig::MISSING_ERROR_POLICY == IGNORE_UNKNOWN || \
        type_if_exists_##event_name<config::TheConfig>::exists, \
        "COM event " #event_name " can be reportet, but is not configured."); \
    std::conditional<type_if_exists_##event_name<config::TheConfig>::exists, \
        ReportEvent<type_if_exists_##event_name<config::TheConfig>::type>, \
        IgnoreEvent>::type()() \
}

- SFINAE ?

+4

Source: https://habr.com/ru/post/1624121/


All Articles