c++11 中的 constexpr 模板 meta-info 变量

constexpr template meta-info variable in c++11

我试图以结构化的方式表示一些元信息(即使用 class)。它是 header-only,我需要支持 c++11,所以不能使用内联变量。我想出了几个可能的解决方案,但每个都有其缺点。任何建议将不胜感激,尽管仅指出如何制作“替代 B”进行编译对我来说是一个很好的解决方案。

SthInfo::fieldA 用作模板化 Processor<Type>::work(field) 的参数,其中 :

备选方案 A - 工作但模板化 ID

#include <type_traits>

template <typename Container, int ID>
class FieldInfo {
public:
    static constexpr int id = ID;
};

template <typename T>
class Processor {
public:
    template <typename Container, int ID>
    void work(FieldInfo<Container, ID> field) {
        static_assert(std::is_same<Container, T>::value, "Given field can't be processed - container type mismatch");
        // some business logic using the ID, i.e. accessing `field.id`
        int id = field.id;
    }
};

struct Sth {/* contains fieldA and fieldB - just as an example */};

// SthInfo holds meta-information about fields in Sth
struct SthInfo {
    static constexpr FieldInfo<Sth, 1> fieldA{};
};

int main() {
    Processor<Sth> processor;
    processor.work(SthInfo::fieldA);
}

这在 Linux 和 Windows 上运行良好(编译和 links)。但是,有没有办法避免模板中的 ID 常量并将其作为 FieldInfo class 中的字段?还有其他改进想法吗?

选项 B - 损坏 - 不会 link

我已经尝试更改为以下代码,但它在 Linux 上没有 link(但在 Windows... 上没有 undefined reference to SthInfo::fieldA):

#include <type_traits>

template <typename Container>
class FieldInfo {
public:
    const int id;
};

template <typename T>
class Processor {
public:
    template <typename Container>
    void work(FieldInfo<Container> field) {
        static_assert(std::is_same<Container, T>::value, "Given field can't be processed - container type mismatch");
        // some business logic using the ID, i.e. accessing `field.id`
        int id = field.id;
    }
};

struct Sth {/* contains fieldA and fieldB - just as an example */};

// SthInfo holds meta-information about fields in Sth
struct SthInfo {
    static constexpr FieldInfo<Sth> fieldA{1};
};

int main() {
    Processor<Sth> processor;
    processor.work(SthInfo::fieldA);
}

替代 C - constexpr 函数 - 不太好用。

SthInfo::fieldA 更改为 constexpr 函数会有所帮助,但在应用程序代码中使用时必须使用 ()...

#include <type_traits>

template <typename Container>
class FieldInfo {
public:
    const int id;
};

template <typename T>
class Processor {
public:
    template <typename Container>
    void work(FieldInfo<Container> field) {
        static_assert(std::is_same<Container, T>::value, "Given field can't be processed - container type mismatch");
        // some business logic using the ID, i.e. accessing `field.id`
        int id = field.id;
    }
};

struct Sth {/* contains fieldA and fieldB - just as an example */};

// SthInfo holds meta-information about fields in Sth
struct SthInfo {
    static constexpr FieldInfo<Sth> fieldA() { return FieldInfo<Sth>{1}; }
};

int main() {
    Processor<Sth> processor;
    processor.work(SthInfo::fieldA());
}

在 C++17 之前,它引入了内联变量——并使 constexpr 静态成员变量隐式内联——你必须在 class 之外 定义 这样的变量,如果他们是 odr-used:

const FieldInfo<Sth> SthInfo::fieldA;

请注意,这是一个 non-templated 变量,因此必须恰好在 一个 源文件中定义。 templated 变量的类似定义可以出现在 headers 中(使用与内联变量相同的 compiler/linker 支持),因此您需要使用类似

template<class T>
struct Info {
    static constexpr FieldInfo<T> fieldA{1};
};
template<class T> const FieldInfo<T> Info<T>::fieldA;