0

我想使用枚举值作为索引来访问元组项。我已阅读这篇文章以提供帮助。
我在 VS2013 中工作,因此如果auto没有trailing return.
静态转换工作,但它很麻烦,而且它要求元组可以自由访问(在实际代码中,属性在protected范围内)。
我想通过使用模板化方法来改进这一点GetAttribute
我试过了,但它产生了一个错误:

prog.cpp:30:119: 错误: '' 和 'size_t {aka unsigned int}' 类型的无效操作数到二进制 'operator<' auto GetAttribute(AttributeName attributeName) -> decltype(std::declval(std::get (attributeName)>(attributes))) ^ prog.cpp:30:119: 错误:''和'size_t {aka unsigned int}'类型的无效操作数到二进制'operator<' prog.cpp:在函数'int main ()': prog.cpp:57:4: 错误: 'struct X' 没有名为 'GetAttribute' 的成员 x.GetAttribute(XParameters::PARAMETER1); // 不编译。^

现场演示

#include <tuple>
#include <cstddef>
#include <utility>
#include <iostream>

enum class XParameters : unsigned int
{
    PARAMETER1, // int
    PARAMETER2, // float
    MAX,
};

enum class YParameters : unsigned int
{
    PARAMETER3 = XParameters::MAX // std::string
};

using XTuple = std::tuple<int, float>;
using YAttributes = std::tuple<std::string>;
using YTuple = decltype(tuple_cat(XTuple(), YAttributes()));

template <typename Attributes>
struct Common
{
    Common(Attributes&& attr) : attributes(std::move(attr)) {}

    Attributes attributes;

    template <typename AttributeName>
    auto GetAttribute(AttributeName attributeName) -> decltype(std::declval(std::get<static_cast<size_t>(attributeName)>(attributes)))
    {
        return std::get<static_cast<size_t>(attributeName)>(attributes);
    }
};

struct X : Common<XTuple>
{
    X() : Common(std::make_tuple(42, 3.14f)) {}
};

struct Y : Common<YTuple>
{
    Y() : Common(std::make_tuple(666, 0.01f, "string")) {}
};

int main()
{
    X x;
    Y y;

    int parameter1 = std::get<static_cast<size_t>(XParameters::PARAMETER1)>(x.attributes); // Compiles, works.
    std::cout << parameter1 << std::endl;

    std::string parameter3 = std::get<static_cast<size_t>(YParameters::PARAMETER3)>(y.attributes); // Compiles, works.
    std::cout << parameter3 << std::endl;

    // Shorter code
    x.GetAttribute(XParameters::PARAMETER1); // Does not compile.

    //parameter3 = std::get<static_cast<size_t>(YParameters::PARAMETER3)>(x.attributes); // Does not compile, phew...

    return 0;
}
4

1 回答 1

2

恐怕不会有很好的解决方案。

丑陋的变种 - 在呼叫现场演员

实现类似功能的最简单方法是将值作为非类型模板参数传递:

template <size_t attributeName>
auto GetAttribute() -> decltype(std::get<attributeName>(attributes))
{
    return std::get<attributeName>(attributes);
}

这会使调用变得丑陋,因为您必须在那里进行演员表:

x.GetAttribute<static_cast<size_t>(XParameters::PARAMETER1)>();

不那么丑陋的变体 - 关联的枚举类型

您可以通过将枚举类型与 Common 类相关联来解决此问题,如下所示:

template <typename Attributes, typename EnumType>
struct Common
{
    Common(Attributes&& attr) : attributes(std::move(attr)) {}

    Attributes attributes;

    template <size_t attributeName>
    auto GetAttribute() -> decltype(std::get<attributeName>(attributes))
    {
        return std::get<attributeName>(attributes);
    }

    template <EnumType attributeName>
    auto GetAttribute() -> decltype(GetAttribute<static_cast<size_t>(attributeName)>())
    {
        return GetAttribute<static_cast<size_t>(attributeName)>();
    }

};

这将允许这样调用:

struct X : Common<XTuple, XParameters>
{
    X() : Common(std::make_tuple(42, 3.14f)) {}
};

x.GetAttribute<XParameters::PARAMETER1>();

显然,您需要为每个 Common 实例指定一个枚举。

最佳变体(?) - 免费(重载)功能

在这种情况下,您只需使用原始元组。然后你滚动你自己的函数(例如GetAttribute),你为你的特定类型的元组和枚举重载:

template <XParameters attributeName>
auto GetAttribute(XTuple &tuple) -> decltype(std::get<static_cast<size_t>(attributeName)>(tuple) )
{
    return  std::get<static_cast<size_t>(attributeName)>(tuple);
}

GetAttribute<XParameters::PARAMETER1>(x.attributes);

在这种情况下定义GetAttribute有很多样板代码,因此您可能希望将其隐藏在宏后面:

#define DEFINE_GetAttribute(ENUM_TYPE, TUPLE_TYPE)                             \
  template <ENUM_TYPE attributeName>                                           \
  auto GetAttribute(TUPLE_TYPE &tuple)                                         \
      ->decltype(std::get<static_cast<size_t>(attributeName)>(tuple)) {        \
    return std::get<static_cast<size_t>(attributeName)>(tuple);                \
  }

DEFINE_GetAttribute(XParameters, XTuple)
于 2016-02-18T12:25:07.690 回答