首页 > 解决方案 > 类成员的 C++ 条件布局

问题描述

我希望根据模板参数重新排列班级成员

class Empty1 { };
class Empty2 { };
class Empty3 { };
class Empty4 { };
class Empty5 { };
class Empty6 { };

class Layout1 { public: uint32_t val1; float val2; bool val3; };
class Layout2 { public: uint32_t val1; bool val3; float val2; };
class Layout3 { public: float val2; uint32_t val1; bool val3; };
class Layout4 { public: float val2; bool val3; uint32_t val1; };
class Layout5 { public: bool val3; uint32_t val1; float val2; };
class Layout6 { public: bool val3; float val2; uint32_t val1; };

template<uint8_t I>
class Item :
    public std::conditional<(I % 6) == 0, Layout1, Empty1>::type,
    public std::conditional<(I % 6) == 1, Layout2, Empty2>::type,
    public std::conditional<(I % 6) == 2, Layout3, Empty3>::type,
    public std::conditional<(I % 6) == 3, Layout4, Empty4>::type,
    public std::conditional<(I % 6) == 4, Layout5, Empty5>::type,
    public std::conditional<(I % 6) == 5, Layout6, Empty6>::type
{
public:
    uint32_t getVal1() const { return val1; }
    float getVal2() const { return val2; }
    bool getVal3() const { return val3; }
};

这个例子应该产生不同的 val1,val2,val3 顺序,因此在不同的 I 值上有不同的内存布局所有所有成员在任何情况下都存在,但是即使没有使用类,我在 Visual Studio 中也不断收到错误 C3861 我该如何修复它,或者也许有人知道另一种方法?

GCC 错误信息

prog.cpp: In member function ‘uint32_t Item<I>::getVal1() const’:
prog.cpp:28:39: error: ‘val1’ was not declared in this scope
     uint32_t getVal1() const { return val1; }
                                       ^~~~
prog.cpp: In member function ‘float Item<I>::getVal2() const’:
prog.cpp:29:36: error: ‘val2’ was not declared in this scope
     float getVal2() const { return val2; }
                                    ^~~~
prog.cpp: In member function ‘bool Item<I>::getVal3() const’:
prog.cpp:30:35: error: ‘val3’ was not declared in this scope
     bool getVal3() const { return val3; }
                                   ^~~~

标签: c++conditional-statementsstd

解决方案


这与依赖基类有关。因为模板的基类依赖于模板参数,所以基类名称是依赖名称。发生这种情况时,编译器无法轻易知道该名称val1是否是从基类继承的。

因此,您必须使用它继承的基类明确限定这些名称。当然,这有点困难,因为您尝试实现整个事情的方式。

使用包含而不是继承会更好,因为无论如何您都必须限定名称。而且您不需要所有那些空结构;您只需要从类型列表中进行选择:

struct Layout1 { std::uint32_t val1; float val2; bool val3; };
struct Layout2 { std::uint32_t val1; bool val3; float val2; };
struct Layout3 { float val2; std::uint32_t val1; bool val3; };
struct Layout4 { float val2; bool val3; std::uint32_t val1; };
struct Layout5 { bool val3; std::uint32_t val1; float val2; };
struct Layout6 { bool val3; float val2; std::uint32_t val1; };

//The tuple is here just as a convenient type-list mechanism.
using LayoutList = std::tuple<Layout1, Layout2, Layout3, Layout4, Layout5, Layout6>;

template<uint8_t I>
struct Item
{
    using DataType = std::tuple_element_t<I % 6, LayoutList>;

    DataType val;

    uint32_t getVal1() const { return val.val1; }
    float getVal2() const { return val.val2; }
    bool getVal3() const { return val.val3; }
};

但是,如果您绝对必须使用基类,则可以使用类似的类型列表:

template<uint8_t I>
using ItemDataType = std::tuple_element_t<I % 6, LayoutList>;

template<uint8_t I>
struct Item : ItemDataType<I>
{
    uint32_t getVal1() const { return ItemDataType<I>::val1; }
    float getVal2() const { return ItemDataType<I>::val2; }
    bool getVal3() const { return ItemDataType<I>::val3; }
};

推荐阅读