Home > Software design >  How to explicitly tell compiler to choose exactly one parameter template during template pack expans
How to explicitly tell compiler to choose exactly one parameter template during template pack expans

Time:06-29

I'm trying using pack parameter template to fit some cases. I want to stop the template packed parameter expanding when there is only one parameter in the list. I want to use the typename explicitly when instancing the template, rather than using the typename to declare variables.

Here is a minimal example:

template <class T>
void f() {}

template <class T, class... Args>
void f() {
  f<Args...>();
}

int main() {
  f<int, int, double>();
  return 0;
}

When compiling the code, I got the error:

demo.cc: In instantiation of ‘void f() [with T = int; Args = {double}]’:
demo.cc:6:13:   required from ‘void f() [with T = int; Args = {int, double}]’
demo.cc:10:23:   required from here
demo.cc:6:13: error: call of overloaded ‘f<double>()’ is ambiguous
    6 |   f<Args...>();
      |   ~~~~~~~~~~^~
demo.cc:2:6: note: candidate: ‘void f() [with T = double]’
    2 | void f() {}
      |      ^
demo.cc:5:6: note: candidate: ‘void f() [with T = double; Args = {}]’
    5 | void f() {
      |      ^

I have read the following information from cppreferrence here:

A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order.

It may be why the compiler can't decide whether to use void f() [with T = double] or void f() [with T = double; Args = {}]

Can I stop the unpacking only by using template parameters rather than using input argument of function?

CodePudding user response:

You can constrain the variadic version of the function with SFINAE to stop it from being called if the parameter pack is empty. That would look like

template <class T, class... Args, std::enable_if_t<(sizeof...(Args) > 0), bool> = true>
void f() {
  f<Args...>();
}
  • Related