Нужна шаблонная функция, которая принимает один из трех контейнеров и печатает его содержимое.
Проблема в том, что у контейнеров разные методы получения элементов.
Мое решение работает если использовать его только для стека, но как только я пытаюсь проделать то же самое для очередей, то получаю ошибку компиляции о невозможности выполнения static_cast.
Что я делаю не так, и есть ли не такой костыльный выриант решения?
template <typename T1>
void Print_sqp(typename T1 t)
{
const std::type_info& info = typeid(t);
const std::type_info& info_stack = typeid(std::stack<T1::value_type>);
const std::type_info& info_queue = typeid(std::queue<T1::value_type>);
const std::type_info& info_p_queue = typeid(std::priority_queue<T1::value_type>);
if (info == info_stack)
{
auto tmp = static_cast<std::stack<T1::value_type>>(t);
while (!(tmp.empty()))
{
std::cout << tmp.top() << " ";
tmp.pop();
}
std::cout << std::endl;
}
else if (info == info_queue)
{
auto tmp = static_cast<std::queue<T1::value_type>>(t);
while (!tmp.empty())
{
std::cout << tmp.front() << " ";
tmp.pop();
}
std::cout << std::endl;
}
else if (info == info_p_queue)
{
auto tmp = static_cast<std::priority_queue<T1::value_type>>(t);
while (!tmp.empty())
{
std::cout << tmp.top() << " ";
tmp.pop();
}
std::cout << std::endl;
}
}
Дело в том, что stack/queue/priority_queue
- это не контейнеры, а ADT. Контейнер, хранящий данные указывается в параметре шаблона.
Для queue
:
template<
class T,
class Container = std::deque<T>
> class queue;
Поэтому для них придётся отдельно специализацию писать.
Может быть есть другие способы, но я не большой эксперт в шаблонах.
Специализация для ADT:
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
template <typename T1>
void Print_sqp(const T1& t)
{
for (const auto& i: t){
std::cout << i << " ";
}
std::cout << std::endl;
}
template<typename T1>
void Print_sqp(const std::stack<T1>& t1){
auto t = t1;
while (!(t.empty()))
{
std::cout << t.top() << " ";
t.pop();
}
std::cout << std::endl;
}
template<typename T1>
void Print_sqp(const std::queue<T1>& t1){
auto t = t1;
while (!t.empty())
{
std::cout << t.front() << " ";
t.pop();
}
std::cout << std::endl;
}
template<typename T1>
void Print_sqp(const std::priority_queue<T1>& t1){
auto t = t1;
while (!t.empty())
{
std::cout << t.top() << " ";
t.pop();
}
std::cout << std::endl;
}
int main()
{
std::stack<int> st;
st.push(1);
std::queue<int> qu;
qu.push(2);
std::priority_queue<int> pqu;
pqu.push(3);
std::vector<int> v;
v.push_back(4);
Print_sqp(st);
Print_sqp(qu);
Print_sqp(pqu);
Print_sqp(v);
return 0;
}
По наводке от AnT
посмотрел внимательнее описание std::stack
, там есть protected
поле Container c
То есть вот так можно ( в дополнении к тому примеру, что перед этим):
...
template<typename T>
class MyStack: public std::stack<T>{
public:
const typename std::stack<T>::container_type& getContainer() const{
return this->c;
}
};
int main()
{
MyStack<int> st;
st.push(1);
...
Print_sqp(st.getContainer());
...
А можно (но выглядит совсем уже неприлично/неправильно) и так:
template<typename T>
class Wrapper: public T{
public:
const typename T::container_type& getContainer() const{
return this->c;
}
};
template<typename T1>
void Print_sqp(const std::stack<T1>& t1){
const auto ptr = static_cast<const Wrapper<std::stack<T1>>*>(&t1);
Print_sqp(ptr->getContainer());
}
template<typename T1>
void Print_sqp(const std::queue<T1>& t1){
const auto ptr = static_cast<const Wrapper<std::queue<T1>>*>(&t1);
Print_sqp(ptr->getContainer());
}
template<typename T1>
void Print_sqp(const std::priority_queue<T1>& t1){
const auto ptr = static_cast<const Wrapper<std::priority_queue<T1>>*>(&t1);
Print_sqp(ptr->getContainer());
}
То, что вы пытаетесь сделать, может быть сделано именно таким способом в С++17. Но записывается это не так и typeid
вам тут не поможет. Здесь нужен if constexpr
#include <type_traits>
#include <stack>
#include <queue>
#include <iostream>
template <typename T>
void Print_sqp(T t)
{
using E = typename T::value_type;
using C = typename T::container_type;
if constexpr (std::is_same<T, std::stack<E, C>>::value)
{
while (!t.empty())
{
std::cout << t.top() << " ";
t.pop();
}
std::cout << std::endl;
}
else if constexpr (std::is_same<T, std::queue<E, C>>::value)
{
while (!t.empty())
{
std::cout << t.front() << " ";
t.pop();
}
std::cout << std::endl;
}
else
{
using CMP = typename T::value_compare;
if constexpr (std::is_same<T, std::priority_queue<E, C, CMP>>::value)
{
while (!t.empty())
{
std::cout << t.top() << " ";
t.pop();
}
std::cout << std::endl;
}
}
}
int main()
{
std::stack<int> s;
s.push(3); s.push(1); s.push(2);
Print_sqp(s);
std::queue<int> q;
q.push(3); q.push(1); q.push(2);
Print_sqp(q);
std::priority_queue<int> pq;
pq.push(3); pq.push(1); pq.push(2);
Print_sqp(pq);
}
При желании вы, однако, можете пойти "классическим" путем без if constexpr
, через перегруженные функции
#include <type_traits>
#include <stack>
#include <queue>
#include <iostream>
template <typename E, typename C>
void Print_sqp(std::stack<E, C> t)
{
while (!t.empty())
{
std::cout << t.top() << " ";
t.pop();
}
std::cout << std::endl;
}
template <typename E, typename C>
void Print_sqp(std::queue<E, C> t)
{
while (!t.empty())
{
std::cout << t.front() << " ";
t.pop();
}
std::cout << std::endl;
}
template <typename E, typename C, typename CMP>
void Print_sqp(std::priority_queue<E, C, CMP> t)
{
while (!t.empty())
{
std::cout << t.top() << " ";
t.pop();
}
std::cout << std::endl;
}
int main()
{
std::stack<int> s;
s.push(3); s.push(1); s.push(2);
Print_sqp(s);
std::queue<int> q;
q.push(3); q.push(1); q.push(2);
Print_sqp(q);
std::priority_queue<int> pq;
pq.push(3); pq.push(1); pq.push(2);
Print_sqp(pq);
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы на него можно было дать ответ, основанный на фактах и цитатах
Вылазит MSB6006 " read access violation**IsRegistered** was nullptr VS 2019