Professor Jimatura
Professor Jimatura

Reputation: 79

How to pass initialization values for the member array in C++ template class arguments?

Let's say I have following template C++ class

template<uint32_t FILTER_ORDER, uint32_t BUFFER_LENGTH>
class Filter {
public:

    Filter() {}

private:
    float data_buffer[BUFFER_LENGTH];
    const float filter_coefficients[FILTER_ORDER + 1];
};

I have been looking for a way how I can pass the coefficients of the filter i.e. individual items of the member array filter_coefficients at compile time. My goal is to have the ability to define filter object in following manner

Filter<3, 8, 1.0, 0.3678, 0.1353, 0.04978> filter;

where the last four non-type arguments of the template are the initialization values for the member array filter_coefficients. Does it exist a way how can I do that in C++?

Upvotes: 1

Views: 80

Answers (1)

Quimby
Quimby

Reputation: 19113

Yes, it is possible in C++20, before that float is not allowed as non-type template parameter.

template<uint32_t FILTER_ORDER, uint32_t BUFFER_LENGTH, float...values>
class Filter {
public:

    Filter() {}

private:
    float data_buffer[BUFFER_LENGTH];
    const float filter_coefficients[FILTER_ORDER + 1]{values...};
};

But this embeds the values into the type, is that really what you want? It will prevent storing arrays of these objects because they now have different types.

I would recommend just using constexpr constructor. Why do you need them to be compile-time anyway?

C++14 variant with constexpr constructor:

#include <cstdint>
#include <array>

template<std::uint32_t FILTER_ORDER, std::uint32_t BUFFER_LENGTH>
class Filter {
public:

    Filter() {}

    template<typename...Floats,typename=decltype(std::array<float,FILTER_ORDER+1>{std::declval<Floats>()...})>
    constexpr Filter(Floats...floats):filter_coefficients{floats...}{}
    
private:
    // Consider using `std::array` here too.
    float data_buffer[BUFFER_LENGTH];
    const float filter_coefficients[FILTER_ORDER + 1];
};

int main(){
    Filter<3, 4> filter{1.0f,2.0f,3.0f,1.0f};
}

There is basic type check to ensure the elements are floats, otherwise this variadic template can shadow some other constructors.

Upvotes: 1

Related Questions