c++c++14

How to use a struct declared with 'constexpr' as a template parameter?


Image you have a struct as follows:

struct DataParameters {
    int a;
    int b[2];
    int c;
};

In a specific situation, you know all these values at compile time:

constexpr DataParameters p = {
    .a = 5,
    .b = {3, 3},
    .c = 12
};

You then want to create a template function which uses the values of a, b, c. The following syntax is valid since the struct is declared as constexpr.

template<int A, int B_0, int B_1, int C>
void doSomething() {
    ...
}

doSomething<p.a, p.b[0], p.b[1], p.c>();

But let's say you have a struct that is much bigger and you do not want a giant list of template parameters. Is there any better way to it? I've tried the following, but get compiler errors:

template<const DataParameters& P>
void doSomething() {
    ...
}

doSomething<p>();

Any suggestions?


Solution

  • Since C++11 you can have template <const DataParameters& P> with objects that have static storage duration and either external or internal linkage.

    Since C++17 you can have template <const DataParameters& P> with objects that have static storage duration (the linkage restriction was removed)

    Since C++20 you can have template <DataParameters P> . The non-type parameter can be (since C++20):

    • a literal class type with the following properties:
      • all base classes and non-static data members are public and non-mutable and
      • the types of all bases classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.

    https://en.cppreference.com/w/cpp/language/template_parameters

    struct DataParameters // don't use C style typedef
    {
        int a;
        int b[2];
        int c;
    };
    
    template <const DataParameters& x>
    void foo() {}
    
    constexpr DataParameters gp{};
    
    void test_ref_global()
    {
        foo<gp>(); // ok since C++11
    }
    
    void test_ref_local()
    {
        static constexpr DataParameters p{};    
        foo<p>(); // ok since C++17
    }
    
    template <DataParameters x> // ok since C++20
    void bar() {}
    
    auto test_val()
    {
        constexpr DataParameters p{};
        bar<p>(); // ok since C++20
    }