Почему эта переменная функция неоднозначна? - PullRequest
3 голосов
/ 18 августа 2011

Это связано с моим предыдущим постом .Я хотел бы знать, почему одна попытка решения не сработала.

template <typename... T>             /* A */
size_t num_args ();

template <>
size_t num_args <> ()
{
    return 0;
}

template <typename H, typename... T> /* B */
size_t num_args ()
{
    return 1 + num_args <T...> ();
}

Если я пытаюсь вызвать, скажем, num_args<int,float>(), то ошибка в том, что вызов функции неоднозначен:

  • A с T = {int, float}
  • B с H = int, T = {float}

Я не понимаю, как это неоднозначно -- A - это объявление, а B - определение функции, объявленной A. Верно?

Я пытаюсь заставить этот пример работать, и ответы на мой предыдущий вопрос, кажется, требуютчто он может никогда работать.

Если это так, в чем смысл свободных функций с переменным числом ?Что могут они делают?

Ответы [ 3 ]

7 голосов
/ 18 августа 2011

Я не понимаю, как это неоднозначно - A является декларацией, а B такое определение функции, объявленной А. Верно?

Нет. A - это объявление шаблона функции, а B - это объявление (и определение) другого шаблона функции.

Компилятор не может выбирать между двумя: у них обоих нет аргументов, а аргументы шаблона совпадают для обоих.

То, что в середине, является явной полной специализацией шаблона функции, объявленного в A.

Если вы пытались сделать B другой специализацией A:

template <typename H, typename... T> /* B */
size_t num_args<H, T...>()
{
    return 1 + num_args <T...> ();
}

... в итоге вы получите частичную специализацию шаблона функции, что недопустимо.

Вы можете сделать это с помощью обычного приема использования шаблона класса с частичной специализацией и шаблона функции, который вызывает шаблон класса:

template <typename... T>
class Num_Args;

template <>
struct Num_Args <>
{
    static constexpr size_t calculate() {
        return 0;
    }
};

template <typename H, typename... T>
struct Num_Args <H, T...>
{
    static constexpr size_t calculate() {
        return 1 + Num_Args<T...>::calculate();
    }
};

template <typename... T> /* B */
constexpr size_t num_args ()
{
    return Num_Args<T...>::calculate();
}
3 голосов
/ 19 августа 2011

По поводу полезности / бесполезности бесплатных шаблонов функций с переменным числом аргументов: обычным вариантом их использования является наличие списка параметров функции с переменным числом аргументов, в этом случае обычная перегрузка для пустого регистра прекрасно подойдет:

size_t num_args()
{
    return 0;
}

template <typename H, typename... T> /* B */
size_t num_args (H h, T... t)
{
    return 1 + num_args(t...);
}


EDIT:

Насколько я понимаю, следующее злоупотребление enable_if должно работать как решение вашего первоначального вопроса:

#include <utility>

// Only select this overload in the empty case 
template <typename... T>
typename std::enable_if<(sizeof...(T) == 0), size_t>::type
num_args() 
{ 
    return 0;
}

template <typename H, typename... T>
size_t
num_args() 
{
    return 1 + num_args<T...>();
}

(Edit2: обратный порядок перегрузок, чтобы код действительно компилировался)

0 голосов
/ 18 августа 2011

Проблема здесь в том, что также перехватывает пустые списки, поэтому, поскольку у вас есть пустая перегрузка в качестве привязки рекурсии, он видит оба и не знает, какой выбрать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...