简体   繁体   中英

C++: template class with many non-typename parameters

I am trying to understand what is the best way to handle a template class with many non-typename parameters.

What I want to avoid is something like:

template <int parameter1,
  int parameter2,
  int parameter3,
  ...
  int parameterN>
class Foo {
  void bar();
};

template <int parameter1, int parameter2, int parameter3, ..., parameterN>
void Foo::bar() {
  // a function of parameter1, parameter2, ..., parameterN
}

One possible solution is packing constexpr inside a struct, like this:

struct ParametersSetA {
  static constexpr int parameter1 = ...;
  ...
  static constexpr int parameterN = ...;
};

template <typename ParametersSet>
class Foo {
  void bar();
};

template <typename ParametersSet>
void Foo::bar() {
  // a function of ParametersSet::parameter1, ..., ParametersSet::parameterN
}

This is a pretty subjective question (define "best"). IMO, using a struct would be ideal. But using structs as template parameters is only supported in C++20.

struct Config {
    int a; 
    int b;
    int c;
};

template <Config config>
struct Foo {
    int bar(int a, int b, int c) {
        return config.A*a + config.B*b + config.c*c;
    }
};

/* ... */

Foo<Config {1, 2, 3}> foo;

I have seen parameters hidden using a type:

template <int A, int B, int C>
struct ConfigPack {};

template <typename Config>
struct Foo {
    int bar(int a, int b, int c);
};

/* ... */

using Config = ConfigPack<1, 2, 3>;
Foo<Config> foo;

And then either overloading or partial specialization used for those methods which actually need the parameters:

template <int A, int B, int C>
int multiply_accumulate(int a, int b, int c, ConfigPack<A, B, C>) {
    return A*a + B*b + C*c;
}

template <typename Config>
int Foo::bar(int a, int b, int c) {
    return multiply_accumulate(a, b, c, Config{});
}

For your contrived example, with all the parameters being the same type and combined in a formulaic way, you can use a variadic template to simplify the formula (or depending on your point of view, make it horribly more complicated than it needs to be):

template <int... Is>
class Foo {
    // using C++17 fold expressions
    void bar(decltype(Is)... args) {
        return ((Is * args) + ...);
    }

    // a bit less elegant, but works in C++11
    void bar(decltype(Is)... args) {
        auto terms = { (Is * args)... };
        return std::accumulate(terms);
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM