【问题标题】:Using template meta programming (TMP) to make homogeneously storable templated configurants使用模板元编程 (TMP) 制作同构可存储的模板化配置
【发布时间】:2020-04-01 08:08:47
【问题描述】:

很抱歉这个残暴的标题。

场景是我的程序中有一个配置系统,它需要能够保存所有类型的值。这些值(配置)需要保存在同质容器中。

例如:(这是伪代码,我不确定它的实际外观)

configurant i(64);
configurant b(true);
configurant f(128.f);
configurant custom(Color(255, 255, 255));

vector<configurant> confs;
confs.emplace_back(i);
confs.emplace_back(b);
confs.emplace_back(f);
confs.emplace_back(custom);

// some form of accessing the vector with proper configurant type here:
// casting?

就像我说的,我不知道这个系统在实践中会是什么样子。我知道这样的声明

auto color = confs.at(3).rgb();

在 C++ 中通常是不可能的,但是我可以用模板化元编程做些什么来尝试尽可能接近这个解决方案吗? (也许配置器可以映射到它们的类型?但这不会是编译时操作)

我希望创建一个可同质存储、立即访问(不存储在堆上)并在编译时评估操作有效性的系统。

欢迎任何建议。

在 cmets 进来之前,我已经尝试过 std::any/std::any_caststd::variant、访问者模式和其他类似性质的东西。我不想使用任何这些系统。

编辑 为避免混淆,有 N 个配置器:它不是一组静态大小的配置器。此界面的用户将添加更多配置项。

编辑 2 所需用法的其他示例

class foo {
configurant enabled;
configurant bar;
public:
    foo() {
        this->enabled = configurant(true);
        this->bar = configurant(5);
    }

    void body() {
        if(this->enabled) {
            std::cout << (this->bar < 100) << "\n";
        }
    }

    // It also needs to be kept in mind that these configurant classes
    // cannot be templated (directly, at least), since they need to be stored in 
    // a homogeneous container.
};

【问题讨论】:

  • Do confs 必须是 vectorconfigurant。还是tuple&lt;int,bool,float,Color&gt;
  • 这个接口意味着能够接受任何和所有类型。所以元组不起作用。 int、bool、float 和 Color 只是我决定使用的四个示例。有 N 个配置项,而不是静态数量。很抱歉造成混乱。
  • 因此任何数据类型都可以存储在具有任意数量元素的存储的 any 索引中,但编译器必须检查在任何这些索引处执行的操作是否一致与存储的数据? (啊!好吧,我想我明白了:我们今天是 4 月 1 日!这很好,谢谢;^)
  • @prog-fh 是的,这基本上就是我所追求的。当你这样说的时候,听起来越来越不可能了。
  • 正如@generic_opto_guy 所建议的,最接近的解决方案依赖于std::tuple,但必须在编译时选择存储数据的数量、顺序和类型。

标签: c++ templates metaprogramming


【解决方案1】:

因为这个要求 "在编译时评估操作的有效性。", 这意味着您的示例 auto color = confs.at(3).rgb(); 仅适用于编译时已知的 index 3 (为什么不24?)。
这个索引在这种情况下不是很相关/有用。

如果您只考虑一个结构提供 具有正确名称而不是 编译时索引

struct Confs
{
  configurant<int> i;
  configurant<bool> b;
  configurant<float> f;
  configurant<Color> custom;
};

...
Confs confs{64, true, 128.f, Color(255, 255, 255)};
auto color = confs.custom.rgb();

这样的事情可能依赖于编译时索引 但我并没有真正看到指定成员的好处。

auto confs=std::make_tuple(64, true, 128.0f, Color{255, 255, 255});
auto color = std::get<3>(confs).rgb();

【讨论】:

  • 谢谢,但这并不是我想要的。该接口应该能够接受任何和所有类型。还有 N 个配置项,这意味着在这种情况下,静态大小的结构将不起作用。关于您的第一条语句(为什么不索引24),我这样写是因为访问.rgb() 成员以获取“bool”或“int”值(应该)是未定义的行为。 (另外,没有索引4
  • @marcyeo 所以句子 “在编译时评估操作的有效性。” 具有误导性。对不起,我不明白这个要求。
  • 例如,如果我要做auto test = confs.at(1); 然后尝试在if(test) {} 中评估它,那应该可以。如果我要执行auto test_2 = confs.at(3);if(test_2) {},那不应该工作,因为Color 类不能以这种方式评估,而bool 是。使用静态类型的 C++,我知道这种确切的行为是不可能的。
  • 我将在主帖中添加一个我想要使用的示例。
猜你喜欢
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-11
  • 1970-01-01
  • 2013-05-06
  • 1970-01-01
相关资源
最近更新 更多