如果存在具有特定名称的结构成员,则强制编译失败

Force compilation to fail if a struct member with a particular name exists

本文关键字:失败 编译 成员 结构 存在 定名称 如果      更新时间:2023-10-16

假设bad_name是一个受限制的标识符,例如,我不想成为结构的一部分。在这种情况下,我正在寻找一种强制编译失败的机制。

示例.h

struct example {
  int okay_name;
  int bad_name; 
}

main.cc

#include "example.h"
int main() {
  example ex;
  // cause compilation to fail here if bad_name is a member of ex
  return 0;
}

可能有一些方法可以通过模拟反射在运行时导致失败,但有没有一种方法可以在编译时做到这一点?

您可以将bad_name定义为会导致编译时错误的内容。例如,什么都没有:

#define bad_name

在GCC 上给出

错误:声明没有声明任何东西[-fpermission]

int bad_name;

您可以在C中模拟静态断言,如下所示:

#define bad_name xxx; char static_assertion_bad_name_used[-1];
struct example {
  int okay_name;
  int bad_name;
};

GCC中给出的是:

main.c:6: error: size of array ‘static_assertion_bad_name_used’ is negative

这种技术的优点是,错误消息会提醒您问题所在(即使有点模糊)。

更新阅读本文后,我发现如果数组大小为负数,MS Visual Studio不会在错误消息中包含实际变量名。这里有一个替代方案:

#define bad_name xxx; int static_assertion_bad_name_used : 0;

GCC中的错误消息是:

main.c:5: error: zero width for bit-field ‘static_assertion_bad_name_used’

显然在VS中也有类似的东西。

此外,如果使用最新的编译器,您可以使用_Static_assert,它会更干净。

您可以使用以下内容:

#include <cstdint>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)               
    template <typename U>                                                   
    class traitsName                                                        
    {                                                                       
    private:                                                                
        template<typename T, T> struct helper;                              
        template<typename T>                                                
        static std::uint8_t check(helper<signature, &funcName>*);           
        template<typename T> static std::uint16_t check(...);               
    public:                                                                 
        static                                                              
        constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); 
    }
DEFINE_HAS_SIGNATURE(has_bad_name, T::bad_name, decltype(&T::bad_name));

然后用static_assert(需要C++11)进行检查:

static_assert(!has_bad_name<example>::value, "");

假设bad_name是一个受限制的标识符,例如我没有希望成为结构的一部分。我正在寻找一种机制来强制在这种情况下编译失败。

这不是完全可移植的,但至少在VC++和GCC中,您可以将标识符标记为不推荐使用,如果需要,还可以提升它向错误发出的警告。