Так что я пытаюсь понять вариадические шаблоны немного больше,
Моей целью было получить все типы, расширить их и распечатать их ..
Я был в состоянии сделать это для функции (нашел несколько примеров), но я не смог сделать это для класса
Здесь я пытаюсь создать «Мастера», который будет содержать много «Рабов», каждый Раб должен иметь наследство 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
Прежде всего: Чтобы разрешить полиморфные шаблоны, вы определили не шаблонный чисто виртуальный базовый класс 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#
Других решений пока нет …