检查类型是否通过static_assert定义?

huangapple go评论77阅读模式
英文:

Check if a type is defined via static_assert?

问题

I have a situation where I have an enum that defines a list of jobs.

enum class job_t
{
  a,
  b,
  c,
};

Elsewhere I have classes that subclass an interface like

class job_interface
{
  public:
    virtual job_t get_job_type(void) const = 0;
    /* ... other methods snipped for simplicity */
}

What I want to do is verify for each value of the job_t enum that a class exists that subclasses job_interface with the same name. I have access to magic_enum so I am wondering if it's possible to translate the enum values to compile time strings and then detect if they're valid typenames via static_assert. It would also be nice if I could verify those classes were descendants of job_interface.

Any suggestions on how I might achieve this?

英文:

I have a situation where I have an enum that defines a list of jobs.

enum class job_t
{
  a,
  b,
  c,
};

Elsewhere I have classes that subclass an interface like

class job_interface
{
  public:
    virtual job_t get_job_type(void) const = 0;
    /* ... other methods snipped for simplicity */
}

What I want to do is verify for each value of the job_t enum that a class exists that subclasses job_interface with the same name. I have access to magic_enum so I am wondering if it's possible to translate the enum values to compile time strings and then detect if they're valid typenames via static_assert. It would also be nice if I could verify those classes were decendants of job_interface

Any suggestions on how I might achieve this?

答案1

得分: 1

Identifier names can't be obtained from strings, even if they're compile-time. The best you can do is macros, e.g. with X macros.

To define the enum:

#define X(id) id,
enum class job_t {
    JOB_IDS
};
#undef X

Checking for existence is a bit hard. Checking for completeness is easier, which should suffice for your case. To check for completeness of a type T, we SFINAE on sizeof(T):

template<typename T>
constexpr auto is_complete(T*) -> decltype(!sizeof(T))
{
    return true;
}

constexpr auto is_complete(void*)
{
    return false;
}

Then bundle the completeness check together with the base class check:

template<typename T>
constexpr auto check(T*) -> decltype(!sizeof(T))
{
    return std::is_base_of_v<job_interface, T>;
}

constexpr auto check(void*)
{
    return false;
}

Finally, we abuse the fact that struct a* is valid regardless of whether a is defined or not:

#define X(id) \
static_assert(check((struct id*)nullptr), #id" has to be defined and inherit from job_interface");
JOB_IDS
#undef X

Live.

英文:

Identifier names can't be obtained from strings, even if they're compile time. The best you can do is macros, e.g. with X macros

#define JOB_IDS \
    X(a) \
    X(b) \
    X(c)

To define the enum

#define X(id) id,
enum class job_t {
    JOB_IDS
};
#undef X

Checking for existence is a bit hard. Checking for completeness is easier, which should suffice for your case. To check for completeness of a type T, we SFINAE on sizeof(T)

template&lt;typename T&gt;
constexpr auto is_complete(T*) -&gt; decltype(!sizeof(T))
{
    return true;
}

constexpr auto is_complete(void*)
{
    return false;
}

Then bundle the completeness check together with the base class check

template&lt;typename T&gt;
constexpr auto check(T*) -&gt; decltype(!sizeof(T))
{
    return std::is_base_of_v&lt;job_interface, T&gt;;
}

constexpr auto check(void*)
{
    return false;
}

Finally, we abuse the fact that struct a* is valid regardless of whether a is defined or not

#define X(id) \
static_assert(check((struct id*)nullptr), #id&quot; has to be defined and inherit from job_interface&quot;);
JOB_IDS
#undef X

Live.

huangapple
  • 本文由 发表于 2023年5月15日 15:49:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76251917.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定