Расширение шаблонов Variadic рекурсивно для классов и функций

Так что я пытаюсь понять вариадические шаблоны немного больше,
Моей целью было получить все типы, расширить их и распечатать их ..
Я был в состоянии сделать это для функции (нашел несколько примеров), но я не смог сделать это для класса
Здесь я пытаюсь создать «Мастера», который будет содержать много «Рабов», каждый Раб должен иметь наследство Slave_T от него, а затем узнать его тип и напечатать его на c’or.

Но по какой-то причине я не могу исправить неоднозначную ошибку компиляции. Я пытался избежать передачи любого типа в качестве параметров функции. Я пытался с соглашениями enable_if или true / false_type, но не смог, у кого-либо есть идеи ?
Это мой код: (расширение функции включено)

Расширение функции, которое работает:

template<typename T, typename... Targs>
void Print(T value, Targs... Fargs) // recursive variadic function
{
Print<T>();
Print(Fargs...); // recursive call
}

template<typename T>
void Print(T = NULL)
{
std::cout << typeid(T).name() << endl;
}

Расширение класса, в котором мне нужна помощь:

#include <iostream>
#include <vector>
#include <type_traits>
#include <memory>
using namespace std;struct Slave {
virtual char const* Type() = 0;
};

template<typename T>
struct Slave_T : public Slave{
virtual char const* Type() {
return typeid(T).name();
}
};

template <typename ...T>
struct Master {
Master()
{
MakeSlave<T...>();
cout << "All Slaves:" << endl;
for (auto const& slave : v){
cout << slave ->Type() << endl;
}
}
private:

template<typename T, typename ...Rest>
void MakeSlave()
{
MakeSlave<Rest...>(); MakeSlave<T>();
}

template<typename T>
void MakeSlave()                    {
v.push_back(new Slave_T<T>());
}

vector<shared_ptr<Slave>> v;
};

int main()
{
Master<int, double, char> m;
//Print("Hello", '!', 123, 123);
return 0;
}

Спасибо!

Alon

3

Решение

Прежде всего: Чтобы разрешить полиморфные шаблоны, вы определили не шаблонный чисто виртуальный базовый класс Slave, Ваш шаблон класса Slave_T должен наследовать от него (вы хотите std::vector содержащие гетерогенные шаблоны, верно?). И обратите внимание, что вы используете виртуальную функцию, определенную базовым классом Slave, Я думаю, что вы забыли написать список базовых классов, прежде чем struct Slave_T 🙂

Во-вторых: В этом переопределении виртуальной функции Type(), ты написал Slave<T>::type вместо Slave_T<T>::type, Также обратите внимание, что это предложение необходимо typename Ключевое слово перед ним, потому что является ссылкой на зависимую область.. Но, с другой стороны, у вас есть доступ к Slave_T шаблонный параметр TИтак, почему вы не просто используете T? 🙂

В третьих: Предпочитаю использовать std::make_shared вместо сырого new приговоры.

В-четвертых: предпочитать std::string вместо необработанных строк в стиле C

Изменить после исправления кода:

Шаблонный параметр T частного назначения MakeSlave() затеняет переменную шаблона класса param T, Вы должны использовать другое имя.

Кстати, ошибка в том, что в перегрузках makelave неоднозначно: вы определили версию с параметрами шаблона T и вариадический Paramsто есть типичный ГОЛОВА ХВОСТ рекурсивный подход, используемый с вариационными пакетами. Но, с другой стороны, вы также определяете версию только с одним параметром шаблона. Обратите внимание, что это делает неоднозначность с первой версией, потому что пакет с переменными значениями может быть пустым, поэтому в вашем базовом случае компилятор не знает, какую версию использовать.

Решение:

Вы можете использовать тип часового, чтобы отслеживать, когда список параметров полностью обработан. Этот страж используется для включения / отключения базового варианта, чтобы избежать неоднозначности:

template <typename ...T>
struct Master {
Master()
{
MakeSlave<T...,_my_centinel_type>();
cout << "All Slaves:" << endl;
for (auto const& slave : v){
cout << slave ->Type() << endl;
}
}
private:
struct _my_centinel_type {};

template<typename U, typename ...Rest>
typename std::enable_if<!std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave()
{
v.push_back( std::make_shared<Slave_T<U>>());
MakeSlave<Rest...>();
}

template<typename U>
typename std::enable_if<std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave(){
//The base case does anything
}

Посмотрите это в действии: http://ideone.com/FqMPXh#

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]