C Рекурсивные переменные шаблоны с расширением базового варианта

#c #templates #c 17

#c #шаблоны #c 17

Вопрос:

я хочу использовать рекурсивные переменные шаблоны с базовым вариантом с более чем 2 типами. Следующий пример не компилируется. В чем может быть проблема?

Я ожидал, что f<int, int>(5) вызовет случай, подобный:

[с T = int; Arg = int; Args = {int}]

но, похоже, это не вариант для компилятора (g c 17) 😉

 template<class T, typename Arg, typename... Args>
void f(T a) {
}

template<class T, typename Arg>
void f (T a) {
}


int main() {
    f<int, int>(5);
    return 0;
}
  
 <source>: In function 'int main()':

<source>:11:18: error: call of overloaded 'f<int, int>(int)' is ambiguous

   11 |     f<int, int>(5);

      |                  ^

<source>:2:6: note: candidate: 'void f(T) [with T = int; Arg = int; Args = {}]'

    2 | void f(T a) {

      |      ^

<source>:6:6: note: candidate: 'void f(T) [with T = int; Arg = int]'

    6 | void f (T a) {

      |      ^

Compiler returned: 1
  

Комментарии:

1. Почему вы ожидаете [with T = int; Arg = int; Args = {int}] именно этого? Вы указали 2 int параметра для f . Вы ожидаете Args , что вас выведут из 5 ?

2. Да, я думал, что это сработает. Потому что в этом примере это работает (да, я знаю, что немного по-другому, но я думал, что это будет аналог): template<typename X> int square(X num) { return num * num; } int main() { return square(5); }

3. Разница в том, что вы не указываете аргументы шаблона, поэтому должен выполняться вычет.

Ответ №1:

Вы можете объединить оба случая и использовать оператор constexpr if в шаблоне функции:

 #include <iostream>

template<class T, typename Arg, typename... Args>
void f(T a) {
    std::cout << sizeof...(Args) << 'n';

    if constexpr (sizeof...(Args) > 0) {
        f<T, Args...>(a);
    }
}

int main() {
    f<int, int>(5);

    std::cout << "---n";

    f<int, int, double, float, int>(5);
}
  

Вывод:

 0
---
3
2
1
0