Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a container like std::integral_constant

I would like to create a "container-version" of std::integral_constant. That is a type parametrized with an element-type and non-type parameters:

enum class A {
    a = 1 << 0, 
    b = 1 << 1, 
    c = 1 << 2
};

template<typename T, T... Values>
struct static_container final {};

template<typename T, T... Ts>
constexpr auto make_static_container(T...) { // wrong
    return static_container<T, Ts...>{};
}

template<typename F, F... FF>
void inline set(static_container<F, FF...>) {
    std::cout << sizeof... (FF) << std::endl;
}

int main() {
    constexpr static_container<A, A::a, A::b> sc1{}; //ok
    constexpr auto sc2 = make_static_container(A::a, A::c); // not-ok

    set(sc1);    
    set(sc2);    
}

Above you can see that I can create sc1 with explict type.

Now I like to have a helper function to create such a type without specifying the (redundant) enum-type.

The output here is:

2
0

Any hints?

like image 335
wimalopaan Avatar asked Jul 26 '26 16:07

wimalopaan


2 Answers

As a followup to your comment regarding std::integral_constant, here's what that would look like:

template<typename T, T... Values>
constexpr auto make_static_container(std::integral_constant<T, Values>...) noexcept {
    return static_container<T, Values...>{};
}

The callsite will have to change since the function is now taking std::integral_constant<T>s rather than Ts directly; it is a bit noisier, but variable templates keep it from being too painful:

template<A a>
using A_ = std::integral_constant<A, a>;

template<A a>
constexpr A_<a> a_{};

int main() {
    // explicit construction via alias template:
    constexpr auto sc1 = make_static_container(A_<A::a>{}, A_<A::b>{});
    // implicit construction via variable template:
    constexpr auto sc2 = make_static_container(a_<A::a>, a_<A::c>);

    set(sc1);
    set(sc2);
}

Online Demo

(As an aside, the separate definition of static_container::value in the demo becomes unnecessary in C++17.)

like image 101
ildjarn Avatar answered Jul 28 '26 09:07

ildjarn


Your problem is that you don't pass the arguments of the function to the list of template arguments for the returned value creation

template<typename T, T... Ts>
constexpr auto make_static_container(T... /* !!! unused values !!! */) { // wrong
    return static_container<T, Ts...>{};
}

So the only deduced template is T; no template not-type values Ts are deduced; so the type returned is

return static_container<T>{};

that is with zero values.

You should be able to use the arguments of the function and pass they as template not type paramenters; something like

template<typename T0, typename ... Ts>
constexpr auto make_static_container (T0 const t0, Ts const ... ts)
 { return static_container<T0, t0, ts...>{}; }

but this is impossible (as far I know) in C++11/C++14 because the t0/ts values aren't constexpr values

like image 22
max66 Avatar answered Jul 28 '26 08:07

max66



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!