【问题标题】:c++11 way of returning an array of unknown number of elementsc++11返回未知数量元素数组的方法
【发布时间】:2021-11-26 07:05:26
【问题描述】:

我想在 C++11 中实现这个功能(或类似的功能,请参阅下面的要求):

template<typename... ARGS>
constexpr std::array<const typename std::common_type<ARGS...>::type, sizeof...(ARGS)> asConstArray(ARGS&&... args)
{
    return {std::forward<ARGS>(args)...};
}

struct DataBinding {
    static constexpr auto getRawBindings()
    // HERE          ^- C++14, deduced to std::array<const BindingInfo, 2> in this case
    {
        return asConstArray(
            DEF_BINDING(int, stateProp, stateParam), //BindingInfo constexpr object
            DEF_BINDING(float, areaProp, areaParam)  //BindingInfo constexpr object
            //(...)
        );
    }
};

如你所见,我想介绍一个基于宏的接口(这是必要的,它可以做很多其他与 Qt 相关的魔法)。

DEF_BINDING 返回用户定义结构的 constexpr 对象(BindingInfo - 它包含一些 const char*size_t 成员,它可以替换为任何可以包含相同的结构或模板)。

我不想强迫程序员手动计算绑定,因为这很不方便。上面的解决方案是我能想到的最接近的解决方案,但我想在 C++11 中解决以下问题:

  1. 需要返回一个元素数组(数组之类,使用std::array是 不是必须的)
  2. 必须是编译时
  3. 项目只能定义一次(不想枚举数组元素两次)
  4. 必须是仅标头(静态 constexpr 成员定义在 cpp 文件不能工作,非 ODR 规定的使用可以工作)
  5. 数组大小必须是自动推导出来的

该解决方案可以使用任何类型的 C++11 魔法。我希望我们能弄清楚一些事情:)

更新:在原来的帖子中,我忘了提到一个非常重要的事实:getRawBindings 在结构中。

【问题讨论】:

  • 不清楚实际问题是什么。您有想要移植到 C++11 或其他东西的 C++14 代码?
  • 是的,我的帖子开头的问题是:“我想在 C++11 中实现这个功能(或类似的功能,请参阅下面的要求)”
  • 我只是想知道,既然你的 constexpr 没有参数,为什么不能直接将数组实例化为常量? (使用宏获取程序员输入)
  • 或者只是使用可变参数模板来获取绑定列表。从那里您可以使用 sizeof... 来计算参数的数量,因此在定义返回类型时不需要 auto。
  • @LaurentJospin 因为请求。 4:必须是header-only(cpp文件中定义的静态constexpr成员不能工作,non-ODR规范使用可以工作)。我修改了帖子以强调它。

标签: c++ arrays c++11 templates compile-time


【解决方案1】:

尾随返回类型应该可以完成这项工作:

struct DataBinding {
    static constexpr auto getRawBindings()
    -> decltype(
        asConstArray(
            DEF_BINDING(int, stateProp, stateParam), //BindingInfo constexpr object
            DEF_BINDING(float, areaProp, areaParam)  //BindingInfo constexpr object
            //(...)
        )
    )
    {
        return asConstArray(
            DEF_BINDING(int, stateProp, stateParam), //BindingInfo constexpr object
            DEF_BINDING(float, areaProp, areaParam)  //BindingInfo constexpr object
            //(...)
        );
    }
};

为避免重复,MACRO 可能会有所帮助:

#define RETURN(Expr) decltype(Expr) { return Expr; }

然后

struct DataBinding {
    static constexpr auto getRawBindings()
    -> RETURN(
        asConstArray(
            DEF_BINDING(int, stateProp, stateParam), //BindingInfo constexpr object
            DEF_BINDING(float, areaProp, areaParam)  //BindingInfo constexpr object
            //(...)
        )
    )
};

【讨论】:

  • 啊,加一层宏魔法就好了:) 行得通,我修改了一下:#define DEF_BINDINGS(...) static constexpr auto getRawBindings() -&gt; decltype(asConstArray(__VA_ARGS__)) { return asConstArray(__VA_ARGS__); },所以可以写成:DEF_BINDINGS(DEF_BINDING(QString, state, AdvancedAirwayState)/*...*/)
【解决方案2】:

如何使用尾随返回类型

#include <array>

template<typename... ARGS>
constexpr std::array<const typename std::common_type<ARGS...>::type, sizeof...(ARGS)> 
asConstArray(ARGS&&... args)
{
    return {std::forward<ARGS>(args)...};
}

struct DataBinding {
    template<typename... BINDINGS>
    static constexpr auto getRawBindings(BINDINGS&&... bindings)
    -> decltype(asConstArray(std::declval<BINDINGS>()...))
    // ^^^ trailing return type
    {
        return asConstArray(std::forward<BINDINGS>(bindings)...);
    }
};

然后你可以像这样拨打getRawBindings()

constexpr auto raw_bingdings = DataBinding::getRawBindings(
                                 DEF_BINDING(int, stateProp, stateParam),
                                 DEF_BINDING(float, areaProp, areaParam)
                                 // ...
                               );

【讨论】:

  • 这个想法很棒,但是在这种情况下,绑定的实际枚举将在类之外:( 所以在外面的世界中,我想使用 DataBinding::getRawBindings 而不枚举那里的绑定,比如数据绑定::getRawBindings().
  • 你idea的用法如下: constexpr auto raw_bingdings = DataBinding::getRawBindings( DEF_BINDING(int, stateProp, stateParam), DEF_BINDING(float, areaProp, areaParam) // ... );而不是这个可以简单地写 constexpr auto raw_bindings = asConstArray( DEF_BINDING(int, stateProp, stateParam), DEF_BINDING(float, areaProp, areaParam) //(...));,所以不幸的是它不能解决问题:(
  • @Broothy。我明白你的意思,你可以在DataBinding里面定义static constexpr BindingInfo data[] = {...},通过sizeof(data)得到它的大小,然后用std::index_sequence展开它的元素传递给asConstArray。但是,C++11 中没有index_sequence,需要自己制作轮子。类似this.
  • 我不能使用 static constexpr BindingInfo data[] = {...} 作为成员然后将其作为 Req 展开。 4:必须是header-only(cpp文件中定义的静态constexpr成员不能工作,非ODR规范使用可以工作):(
  • constexpr 变量可以在 c++11 的头文件中声明和实例化。内联变量(在 c++17 中引入),用于在头文件中声明和实例化非常量变量。
猜你喜欢
  • 1970-01-01
  • 2013-05-18
  • 2011-08-05
  • 1970-01-01
  • 2018-04-07
  • 2014-02-01
  • 2023-03-07
  • 1970-01-01
  • 2013-02-12
相关资源
最近更新 更多