如何将预处理器指令扩展到调用预处理器指令的位置之外

How to expand a preprocessor directive outside where it was called

提问人:Cobollatin 提问时间:6/28/2023 更新时间:6/28/2023 访问量:68

问:

我正在试验编译时枚举断言,我想出了以下代码:

template<int Value>
inline constexpr bool isValueUsed(){
    return false;
}

class BaseEnum{
private:
    constexpr BaseEnum(int value): _value(value){
    }
public:
    template<int value>
    constexpr static BaseEnum CreateEnum() {
        static_assert(!isValueUsed<value>(), "The value is already used");
        return BaseEnum(value);
    }

    constexpr BaseEnum& operator=(const BaseEnum& other){
        return *this;
    }

    // public for testing purposes
    int _value;
};

namespace BaseEnumValues {
    constexpr BaseEnum Default = BaseEnum::CreateEnum<0>();
}

#include <iostream>

int main(){
    // Tests Definition
    BaseEnum baseEnum1 = BaseEnumValues::Default;
    BaseEnum baseEnum2 = BaseEnum::CreateEnum<1>();
    // Should fail to compile
    // BaseEnum baseEnum3 = BaseEnum::CreateEnum<1>();

    std::cout << "BaseEnum1: " << baseEnum1._value << std::endl;
    std::cout << "BaseEnum2: " << baseEnum2._value << std::endl;

    return 0;
}

现在,我想在每次调用时都创建模板的专用化,但是我不知道该怎么做,我实现了一个预处理器指令,该指令将扩展到专用化,但是我在函数内部调用它,因此它将在那里扩展,有没有办法将指令扩展到调用位置之外?CreateEnum<>

#define DEFINE_ENUM_VALUE(value) \
    template<> \
    inline constexpr bool isValueUsed<value>(){ \
        return true; \
    }

template<int value>
    constexpr static BaseEnum CreateEnum() {
        static_assert(!isValueUsed<value>(), "The value is already used");
        DEFINE_ENUM_VALUE(value) // This should be expanded elsewhere in the code
        return BaseEnum(value);
    }

关于如何解决这个问题的任何想法?

C++ C++17 模板 -元编程

评论

1赞 Sam Varshavchik 6/28/2023
C++在基本层面上不是这样工作的。撇开语法问题不谈,没有什么可以阻止不同的翻译单元定义相同的枚举值。这里最多可以做的就是编造一些导致ODR使用违规的东西,但这将导致链接失败,而不是编译失败。
0赞 Cobollatin 6/28/2023
@SamVarshavchik ODR 将附加到特定变量而不是值,我希望允许用户创建具有不同值的新变量(或从现有变量中获取引用)。我想使用编译时验证来实现这一点。你确定这是不可能的吗?也许我只是用错了方法?
0赞 BoP 6/28/2023
假设你和我各自用一个枚举编译一个 .cpp 文件。编译器如何知道 - 在编译时 - 值是否不同?
0赞 Cobollatin 6/28/2023
@BoP 嗯,假设我有 BaseEnum.hpp 和 enum1.cpp 和 enum2.cpp每个人都会创建 BaseEnums,如果 isValueUsed() 的所有专用化都在 BaseEnum.hpp 中,那么编译器是否无法访问这两个文件中的那些?
0赞 Igor Tandetnik 6/29/2023
假设并确实定义相同的值。你似乎在说,如果自己编译,它应该会成功。如果自己编译,它应该会成功。但是,如果在编译之后进行编译,那么它应该以某种方式神奇地失败 - 即使没有用作编译输入的文件已更改。您认为有关先前编译会话的信息会以何种方式传递到后续会话中?enum1.cppenum2.cppenum1.cppenum2.cppenum2.cppenum1.cpp

答: 暂无答案