英文:
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<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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论