Home > Enterprise >  c 11 way of returning an array of unknown number of elements
c 11 way of returning an array of unknown number of elements

Time:10-06

I would like to implement this function (or a similar one, see the requirements below) in 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
            //(...)
        );
    }
};

As you see I would like to introduce a macro-based interface (it is necessary, it does a lot of other Qt related magic).

DEF_BINDING returns a constexpr object of an user-defined struct (BindingInfo - it contains a few const char* and size_t members, it can be replaced with any struct or template that can contain the same).

I don't want to force the programmer to count the bindings manually because it would be inconvenient. The solution above is the closest I could figure out, but I would like to solve the followings in C 11:

  1. Needs to return an array of elements (array like, using std::array is not a must-have)
  2. Must be compile time
  3. The items must be defined only once (do not want to enumerate the array elements twice)
  4. Must be header-only (static constexpr member defined in the cpp file cannot work, non-ODR regulated use can work)
  5. The array-size must be auto-deduced

The solution can use any kind of C 11 magic. I hope we can figure out something :)

UPDATE: In the original post I forgot to mention a really important fact: getRawBindings is inside a struct.

CodePudding user response:

How about using trailing return type?

#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)...);
    }
};

Then you can call getRawBindings() like this:

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

CodePudding user response:

Trailing return type should do the job:

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
            //(...)
        );
    }
};

To avoid the repetition, MACRO might help:

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

and then

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