Как заменить set на шаблоны?
От: Аноним  
Дата: 23.10.07 18:53
Оценка:
Есть примерно вот такой код (общая идея):
#include <iostream>
#include <set>

enum Type{ one, two, three, four, five };
struct A{ Type t; A(Type t):t(t){} };

int _tmain(int argc, _TCHAR* argv[])
{
    // два разных множества
    std::set<Type> s1;
    s1.insert(one);
    s1.insert(two);
    s1.insert(three);
    std::set<Type> s2;
    s2.insert(four);
    s2.insert(five);
    // два объекта одного класса с разным типом чего-то внутри
    A a1(one);
    A a4(four);
    // если тип чего-то внутри принадлежит множеству 1, то делаем какие-то действия
    if(s1.find(a1.t) != s1.end())
        std::cout << "in s1 set" << std::endl;
    // то же самое для второго объекта
    if(s2.find(a4.t) != s2.end())
        std::cout << "in s2 set" << std::endl;
    return 0;
}

Мне бы хотелось превратить его во что-то такое:
#include <iostream>

enum Type{ one, two, three, four, five };
struct A{ Type t; A(Type t):t(t){} };

template<Type t>struct Test{ static bool In(Type t); };
template<>static bool Test<one>::In(Type t){ return one == t; }; // здесь все ок
template<>static bool Test<two>::In(Type t){ return two == t; };
template<>static bool Test<three, four, five>::In(Type t) // а вот это я делать не умею :(
{ 
    return three == t || four == t || five == t; 
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a1(one);
     // тут вместо условий пока просто вывожу результат проверки
    std::cout << Test<one>::In(a1.t) << std::endl;
    std::cout << Test<two>::In(a1.t) << std::endl;
    std::cout << Test<three, four, five>::In(a1.t) << std::endl; // соответсвенно это не компилится :(
    return 0;
}

Как это можно сделать наиболее "легким" способом? А может не стоит огород городить и оставить как есть? Хотелось бы найти наиболее правильное решение. Спасибо.
Re: Как заменить set на шаблоны?
От: Sashaka Россия  
Дата: 23.10.07 20:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как это можно сделать наиболее "легким" способом? А может не стоит огород городить и оставить как есть? Хотелось бы найти наиболее правильное решение. Спасибо.


почему бы не сделать так:

template<class T>
bool foo( const set<T>&  set_, const T& value)
{
    return set_.find(value)!=set_.end();
}

set<int> s1;
s1.insert(1);
s1.insert(2);
s1.insert(3);

set<double> s2;
s2.insert(1.1);
s2.insert(2.2);
s2.insert(3.3);
    
assert( foo(s1,1) );
assert( foo(s2,2.) );
Re: Как заменить set на шаблоны?
От: conraddk Россия  
Дата: 23.10.07 21:29
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А> // два разных множества

...
А> // два объекта одного класса с разным типом чего-то внутри
...
А> // если тип чего-то внутри принадлежит множеству 1, то делаем какие-то действия
Если задача именно таких масштабов и показан типичный сценарий использования, почему бы не задействовать "тупой и циничный" вариант:
#include <iostream>

enum Type{ one, two, three, four, five };

struct A{ Type t; A(Type t):t(t){} };

template < int Size >
bool In( const Type (&arr)[Size], Type q )
{
    for( int i=0; i<Size; ++i )
        if( arr[i]==q ) 
            return true;
    return false;
}

int main()
{
    Type s1[] = {one, two, three};
    Type s2[] = {four, five};
    A a1(one);
    A a4(four);
    std::cout <<In(s1, a1.t) <<std::endl;
    std::cout <<In(s1, a4.t) <<std::endl;
    std::cout <<In(s2, a1.t) <<std::endl;
    std::cout <<In(s2, a4.t) <<std::endl;
    return 0;
}

А так — можно соорудить конструкцию по мотивам TypeList и Int2Type Александреску, но надо ли? К тому же, от проблемы с переменным числом параметров в шаблоне оно не избавляет, да и проверяемое значение должно быть известно во время компиляции.
Д.К. << RSDN@Home 1.2.0 alpha rev. 655>>
Все на свете должно происходить медленно и неправильно...
Re: Как заменить set на шаблоны?
От: _Dreamer Россия  
Дата: 24.10.07 04:25
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Есть примерно вот такой код (общая идея):

А>Как это можно сделать наиболее "легким" способом? А может не стоит огород городить и оставить как есть? Хотелось бы найти наиболее правильное решение. Спасибо.

по моему, так не стоит усложнять, если имеющееся решение Вас устраивает.
по приведенной же ситуации можно сделать вот такие варианты —
enum Type{ one, two, three, four, five };

struct null_type{};

template <typename THead, typename TTail>
struct type_list_node
{
    typedef THead head_type;
    typedef TTail tail_type;
};

template < Type t >
struct enum_to_type 
{
    static const Type value = t;
};

template <Type t>
struct Test 
{
    static bool In( Type forTest )
    {
        return t == forTest;
    }
};

template <Type t1, Type t2>
struct Test2
{
    static bool In( Type forTest )
    {
        return Test<t1>::In(forTest) || Test<t2>::In(forTest);
    }
};

template <Type t1, Type t2, Type t3>
struct Test3
{
    static bool In( Type forTest )
    {
        return Test2<t1, t2>::In(forTest) || Test<t3>::In(forTest);
    }
};

template <Type t>
struct enum_list1 : type_list_node< enum_to_type<t>, null_type > {};

template <Type t1, Type t2>
struct enum_list2 : type_list_node< enum_to_type<t1>, enum_list1<t2> > {};

template <Type t1, Type t2, Type t3>
struct enum_list3 : type_list_node< enum_to_type<t1>, enum_list2<t2, t3> > {};

template < typename TList >
class tester
{
    typedef typename TList::head_type head_type;
    typedef typename TList::tail_type tail_type;

    template < typename head, typename tail >
    struct test_impl
    {
        static bool in( Type t )
        {
            return (t == head::value) || tester< tail >::in(t);
        }
    };

    template < typename head >
    struct test_impl<head, null_type>
    {
        static bool in( Type t )
        {
            return (t == head::value);
        }
    };

public :
    static bool in( Type t )
    {
        return test_impl< head_type, tail_type >::in(t);
    }
};

void test()
{
    /* первый вариант */
    bool b = 
        Test<one>::In(one)
        && Test2<one, two>::In(two)
        && Test3<one, two, three>::In(three);

    /* второй вариант */
    b = tester< enum_list1<one> >::in( one );

    b = tester< enum_list2<one, two> >::in( one );

    b = tester< enum_list3<one, two, three> >::in( four );

    return;
}


насколько такие 'огороды' подходят для задачи, решайте сами.
Re[2]: Как заменить set на шаблоны?
От: Кодт Россия  
Дата: 24.10.07 08:39
Оценка:
Здравствуйте, _Dreamer, Вы писали:

_D>по моему, так не стоит усложнять, если имеющееся решение Вас устраивает.

_D>по приведенной же ситуации можно сделать вот такие варианты —
_D>насколько такие 'огороды' подходят для задачи, решайте сами.

Для любителей МосВелосипедСтройМонтажа есть boost/mpl и boost/tuple

А если диапазон перечисления небольшой, то можно и битовые операции задействовать. Тогда не придётся порождать разные воплощения шаблона для разных множеств.
enum BITSET { Nothing = 0, Universe = ~0 };

BITSET single(unsigned item) { assert(item < sizeof(unsigned)*CHAR_BIT); return 1<<item; }

bool subset(BITSET x, BITSET y) { return (x&y)==x; }
bool belongs(unsigned item, BITSET bs) { return subset(single(item),bs); }

Для желающих — можно всё это запихать внутрь шаблона traits, чтобы всё было типизировано до предела. А заодно и BITSET сделать не встроенным типом, чтоб случайно не смешивать множества и элементы.

Ну и в compile time затащить тоже труда не составит, я думаю.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: Как заменить set на шаблоны?
От: Bell Россия  
Дата: 24.10.07 11:35
Оценка:
Здравствуйте, Аноним, Вы писали:

Как вариант:
enum Type{ one, two, three, four, five};
template <Type t>
struct A
{
};

void f(A<one>& a)   { }
void f(A<two>& a)   { }
void f(A<three>& a) { }
void f(A<four>& a)  { }
void f(A<five>& a)  { }


Количество перегрузок при желании можно уменьшить.
Любите книгу — источник знаний (с) М.Горький
Re[3]: Как заменить set на шаблоны?
От: chocho Россия  
Дата: 24.10.07 20:45
Оценка:
К>Для любителей МосВелосипедСтройМонтажа есть boost/mpl и boost/tuple

или кортеж (Tuple) из Loki...
"Не морочьте мне голову. Полыхаев" ©
Re[3]: Как заменить set на шаблоны?
От: _Dreamer Россия  
Дата: 25.10.07 10:30
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Для любителей МосВелосипедСтройМонтажа есть boost/mpl и boost/tuple


Это понятно
Я исходил из того, что, если человек знает о boost/mpl и boost/tuple, то скорее всего, он спросил бы не 'что делать?' а 'что выбрать из следующих вариантов?', как минимум. А то и спрашивать бы не стал.
Поэтому я позволил себе привести идею одного из вариантов решения, естественно, не утверждая что это готовое решение, только вставляй его в код.
Причем как раз без использования сторонних средств вроде буста. Во первых, так мне казалось наглядней, во вторых, думаю так больше шансов, что человек подумает над вариантом, а не просто скопипастит. Естественно, могу быть неправ в своих предположениях.

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