Шаблонная функция для итераторов шаблонных контейнеров
От: Abulafia  
Дата: 11.03.06 10:51
Оценка:
Здравствуйте!

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

template<class T>
std::ostream&
operator<<(std::ostream& st, std::set<T> const& s)
{
     st << '{';
     for(typename std::set<T>::const_iterator i = s.begin();
         i != s.end();
         ++i)
     {
         st << " " << (*i);
     }
     st << '}';
     return st;
}


Теперь можно делать так:

set<int> si;
set<string> ss;
cout << si << ss;
// Всё работает просто на ура!
set<myClass> smc;
cout << smc;
// Работает, если для myClass определён operator<<


Недавно потребовалось хранить в множествах итераторы других контейнеров.
И вот
тут появились проблемы:

   typedef vector<myclass> seq_t;
   typedef seq_t::const_iterator iter_t;
   typedef set<iter_t> set_of_iter_t;
   // Пытаюсь вывести
   set_of_iter_t s;
   cout << s;
   // Правильно, компилятор говорит, что operator << не определен для iter_t


Так вот, вопрос: как написать шаблонную функцию для итераторов?

Пытаюсь сделать так:

template<class T>
std::ostream&
operator<<(std::ostream& st, std::set<T>::const_iterator i)
{
   return st << *i;
}


Но компилятор не находит этот оператор; если же ввести другую функцию с
именем outiter:

template<class T>
void
outiter (std::ostream& st, std::set<T>::const_iterator i)
{
   return st << *i;
}


И вызывать так (для одного элемента):
outiter(cout,  
*s.begin())
,
то компилятор говорит, что не может вывести (Can't deduce) тип параметра
T.

Как правильно сделать?

--
WBR, Abulafia
Posted via RSDN NNTP Server 2.0
Re: Шаблонная функция для итераторов шаблонных контейнеров
От: shank  
Дата: 11.03.06 11:14
Оценка: 1 (1)
Здравствуйте, Abulafia, Вы писали:
Вот так у меня скомпилилось
#include <iostream>
#include <set>
#include <vector>

template<class T>
std::ostream&
outiter (std::ostream& st, typename std::vector<T>::const_iterator i)
{
   return st << *i;
}

typedef std::vector<int> seq_t;
typedef seq_t::const_iterator iter_t;
typedef std::set<iter_t> set_of_iter_t;

set_of_iter_t s;

int main()
{
    seq_t vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    s.insert(vec.begin());

    outiter<int>(std::cout, *s.begin());
}
Re[2]: Шаблонная функция для итераторов шаблонных контейнеро
От: shank  
Дата: 11.03.06 11:22
Оценка:
А вот с оператором >> будут проблемы, так как параметр шаблона надо указывать явно,
потому что вывести параметр шаблона из таких конструкций, (когда параметр шаблона в квалификаторе) невозможно.
 
std::vector<T>::const_iterator i
Re: Шаблонная функция для итераторов шаблонных контейнеров
От: remark Россия http://www.1024cores.net/
Дата: 11.03.06 14:14
Оценка: 3 (1)
Здравствуйте, Abulafia, Вы писали:

A> Так вот, вопрос: как написать шаблонную функцию для итераторов?



Лови

// функция для вывода элементов-итераторов
template<typename T>
void out(std::ostream& stream, const T& v, boost::mpl::int_<sizeof(bool)>)
{
    stream << " " << *v;
}

// функция для вывода обычных элементов
template<typename T>
void out(std::ostream& stream, const T& v, boost::mpl::int_<sizeof(int)>)
{
    stream << " " << v;
}

// SFINAE-based определение, является ли элемент контейнера итератором
template<typename Type>
bool fff(Type*, typename Type::iterator_category* = 0, typename Type::value_type* = 0, typename Type::difference_type* = 0, typename Type::pointer* = 0);
int fff(...);

template<class T>
std::ostream& operator << (std::ostream& stream, std::set<T> const& s)
{
    BOOST_STATIC_ASSERT(( sizeof(int) != sizeof(bool) ));

    stream << '{';
    for (typename std::set<T>::const_iterator i = s.begin(); i != s.end(); ++i)
        out(stream, *i, boost::mpl::int_<sizeof(fff(&*i))>());
    stream << '}';
    return stream;
}



Решение было сделано на скорую руку, поэтому надо доработать напильником. Но тем не менее сейчас решение рабочее для итераторов стандартной библиотеки.
Сейчас не работает для указателей, не работает для итераторов на итератор



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Шаблонная функция для итераторов шаблонных контейнеро
От: remark Россия http://www.1024cores.net/
Дата: 11.03.06 14:17
Оценка:
Здравствуйте, remark, Вы писали:

Да, забыл добавить, если у твоего типа есть typedef'ы iterator_category, value_type, difference_type, pointer, то он будет распознаваться как итератор.
Можно так же проверять на наличие типа reference и на наследование от типа std::iterator, но там есть некоторые технические проблемы — надо думать...


R>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Шаблонная функция для итераторов шаблонных контейнеро
От: Abulafia  
Дата: 12.03.06 04:03
Оценка:
Здравствуйте, remark, Вы писали:

А почему в Вашем коде:

// SFINAE-based определение, является ли элемент контейнера итератором
template<typename Type>
bool fff(Type*, typename Type::iterator_category* = 0, typename Type::value_type* = 0, typename Type::difference_type* = 0, typename Type::pointer* = 0);


используются именно указатели (Type*). У меня и просто с Type заработало. Есть какая-то особенность, или без разницы?
Re: Шаблонная функция для итераторов шаблонных контейнеров
От: Abulafia  
Дата: 12.03.06 04:20
Оценка:
Всем ответившим большое спасибо!

A> Так вот, вопрос: как написать шаблонную функцию для итераторов?


Вот что получилось в результате:


// Using SFINAE for select function
template <typename T>
bool
__outputFunctionSelector(
    T, typename T::iterator_category* = 0, typename T::value_type* = 0, 
    typename T::difference_type* = 0, typename T::pointer* = 0);
int
__outputFunctionSelector(...);


// Using type generating by number
template <size_t SIZE>
class __sizedSelector
{};


// for iterator output
template <typename T>
void
output(std::ostream& st, T const& el, __sizedSelector<sizeof(bool)>)
{
    st << '@' << *el;
}


// for element output
template <typename T>
void
output(std::ostream& st, T const& el, __sizedSelector<sizeof(int)>)
{
    st << el;
}

template<class T>
std::ostream&
operator<<(std::ostream& st, std::vector<T> const& v)
{
    for(size_t i = 0, iEnd = v.size(); i != iEnd; ++i)
    {
        st << (0 == i)?("["):(", ");
        output(st, v[i], __sizedSelector<sizeof(__outputFunctionSelector(v[i]))>());
    }
    return st << ']';
}

template<class TK, class TV>
std::ostream&
operator<<(std::ostream& st, std::map<TK, TV> const& mp)
{
    for(typename std::map<TK, TV>::const_iterator i = mp.begin(); i != mp.end(); ++i)
    {
        st << (i == mp.begin())?("<"):(", ") << '(';
        output(st, i->first, __sizedSelector<sizeof(__outputFunctionSelector(i->first))>());
        st << "->";
        output(st, i->second, __sizedSelector<sizeof(__outputFunctionSelector(i->second))>());
        st << ')';
    }
    return st << '>';
};

template<class T>
std::ostream&
operator<<(std::ostream& st, std::set<T> const& s)
{
    for(typename std::set<T>::const_iterator i = s.begin(); i != s.end(); ++i)
    {
        st << (s.begin() == i)?("{"):(", ");
        output(st, *i, __sizedSelector<sizeof(__outputFunctionSelector(*i))>());
    }
    return st << '}';
}


Теперь можно делать так:

std::set<int> si; 
si.insert(1);
si.insert(2);
si.insert(3);
std::vector< std::set<int> > vsi;
vsi.push_back(si.begin());
std::cout << vsi;


Будет распечатано "@1".

--
WBR.
Re[2]: Шаблонная функция для итераторов шаблонных контейнеро
От: Abulafia  
Дата: 12.03.06 04:22
Оценка:
Здравствуйте, shank, Вы писали:

S>Здравствуйте, Abulafia, Вы писали:

S>Вот так у меня скомпилилось
S>
S>    outiter<int>(std::cout, *s.begin());
S>


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

--
WBR.
Re[3]: Шаблонная функция для итераторов шаблонных контейнеро
От: remark Россия http://www.1024cores.net/
Дата: 15.03.06 10:35
Оценка:
Здравствуйте, Abulafia, Вы писали:

A>Здравствуйте, remark, Вы писали:


A>А почему в Вашем коде:


A>
A>// SFINAE-based определение, является ли элемент контейнера итератором
A>template<typename Type>
A>bool fff(Type*, typename Type::iterator_category* = 0, typename Type::value_type* = 0, typename Type::difference_type* = 0, typename Type::pointer* = 0);
A>


A>используются именно указатели (Type*). У меня и просто с Type заработало. Есть какая-то особенность, или без разницы?



Если там будет просто Type, то как ты его будешь создавать? Type()? А если у него нет конструктора по-умолчанию?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.