Шаблоны Variadic - неполный тип - PullRequest
7 голосов
/ 25 октября 2011

Имея этот код:

template<class ...Args>
struct Are_Same
{
    enum {value = Are_Same<Args...>::value};
};

template<class A,class... C>
struct Are_Same<A,C...>
{
    enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE
};

template<class A,class B>
struct Are_Same<A,B>
{
    enum {value = std::is_same<A,B>::value};
};  

Я получаю ошибку от gcc 4.6.1:

ошибка: неполный тип 'Are_Same' используется в описателе вложенного имени.

Я думал, что, делая Are_Same<A,C...>::value, я вызову рекурсивный вызов, который в конце просто расширится до Are_Same<A,B>.Очевидно, это не тот случай.Кто-нибудь знает, где я делаю ошибку?

Ответы [ 3 ]

8 голосов
/ 25 октября 2011

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

Реализация шаблона are_same variadic может быть:

template <class... Args>                    // base (optional to declare the template)
struct are_same;

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = is_same<A,B>::value && are_same<A,Args...>::value;
};

template <class A, class B>                 // stop condition
struct are_same<A,B> {
    static const bool value = is_same<A,B>::value;
};

Обратите внимание, что на шаге recursion один аргумент удаляется из списка аргументов, поэтому новая проблема, которую необходимо решить, - это уменьшенная версия оригинала. Этот тип шаблонного метапрограммирования тесно связан с рекурсией, и применяются те же правила, чтобы иметь возможность использовать рекурсию, вам нужно убедиться, что каждый рекурсивный шаг приближает вас к решению. В этом конкретном случае, учитывая список из N потенциально одинаковых типов, каждый шаг сводит проблему к нахождению одинаковых N-1 типов.

В качестве условия остановки (заменив прежнее) вы можете использовать альтернативно вырожденную версию проблемы are_same:

template <class A> 
struct are_same<A> {
   static const bool value = true;
};

Что является вырожденным в том смысле, что на самом деле не имеет смысла спрашивать, является ли один тип * are_same *, но для различных задач метапрограммирования это может быть уместным.

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

template <class... Args>
struct are_same;

template <class A, class... Args>
struct are_same<A,A,Args...> {              // recursion
    static const bool value = are_same<A,Args...>::value;
};

template <class A, class B, class... Args>
struct are_same<A,B,Args...> {              // cut, A and B are not the same
    static const bool value = false;
};

template <class A>
struct are_same<A> {                        // end of recursion
    static const bool value = true;
};

В этом случае компилятор предпочтет шаги recursion вместо cut, когда оба типа совпадают, поэтому нам не нужно проверять is_same внутри. В то же время, если компилятор перейдет к шагу cut, нам не нужно обрабатывать оставшуюся часть списка типов, поскольку мы уже знаем ответ.

3 голосов
/ 25 октября 2011

Я бы сделал это так:

#include <type_traits>
#include <iostream> 

template <class... Args>
struct are_same
{
  static const bool value=true;
};

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value;
};

int main()
{
    std::cout<< std::boolalpha << are_same< int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl;
}
0 голосов
/ 31 июля 2013

Вероятно, самая простая реализация может быть такой:

template <typename... TList>
struct are_same { constexpr static bool value = false; };

template <typename T, typename... TList>
struct are_same<T, T, TList...> { 
    constexpr static bool value = are_same<T, TList...>::value; 
};

template <typename T>
struct are_same<T> { constexpr static bool value = true; };

В качестве альтернативы вы можете заменить условие останова на

template <typename T>
struct are_same<T, T> { constexpr static bool value = true; };

Но первое более общее, потому что are_same<type>::value == true.Другой вопрос, что должно быть равно 1008Это дает вам false, но нет ничего сложного в том, чтобы добавить еще одну специализацию шаблона, подобную этой.

template <>
struct are_same<> { constexpr static bool value = true; };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...