Как задать некоторые параметры шаблона?
От: What Беларусь  
Дата: 26.06.04 16:06
Оценка:
Я пишу "библиотечный" класс, с N = 5 стратегиями.
template <typename T1, typename T2, ... , typename TN> class CMyClass;

В большинстве случаев используется один и тот же набор параметров.
Пользователи класса хотят иметь возможность задавать "отклонения" от этого набора.
Например, задать параметр T3, а остальные оставить по умолчанию и даже не задумываться об их значении.
Как это реализовать?

У меня есть несколько вариантов:
1. Параметры по умолчанию:
template <typename T1 = CDefault1, ..., typename TN = CDefaultN> class CMyClass;

Это для пользователей класса неудобно, так как для того, чтобы задать параметр T3, придётся задавать T1 и T2.

2. Использовать traits.
template <typename TID> class CMyClass
{
    typedef CMyClassTraits1<TID>::T T1;
    ...
    typedef CMyClassTraitsN<TID>::T TN;
};

template <typename TAnyID> struct CMyClassTraits1
{
    typedef T CDefault1;
};

template <typename TAnyID> struct CMyClassTraitsN
{
    typedef T CDefaultN;
};

// Использование (задаём третий параметр)
template <> struct CMyClassTraits3<CSomeID>
{
    typedef T CUserPolicy3;
};

class CUserClass
{
    CMyClass<CSomeID> v;
};

Это мне кажется не очень удобным в данной ситуации, так как:
а) Приходится делать тип-идентификатор
б) Для задания каждого параметра нужно писать 3 строки кода

3. "Перегружать" typedef
template <typename TParams> class CMyClass
{
    typedef typename TParams::T1 T1;
    typedef typename TParams::T2 T2;
    ...
    typedef typename TParams::TN TN;
};

// Использование (задаём третий параметр)
struct CUserParams : public CMyClassDefaultParams
{
    typedef CUserPolicy T3;
};

class CUserClass
{
    CMyClass<CUserParams> v;
};

Этот вариант мне больше всего нравится:
а) Прозрачно, просто
б) Для задания каждого следующего параметра + 1 строка кода
в) Можно выделить часто используемые наборы в отедльный h-ник.

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

P.S.
У меня стойкое ощущение, что я изобретаю велосипед
... << RSDN@Home 1.1.3 stable >>
Re: Как задать некоторые параметры шаблона?
От: WolfHound  
Дата: 26.06.04 19:26
Оценка: 20 (2)
Здравствуйте, What, Вы писали:
#include "stdafx.h"
struct default_policy_1{};
struct default_policy_2{};
struct default_policy_3{};
struct default_polices
{
    typedef default_policy_1 policy_1;
    typedef default_policy_2 policy_2;
    typedef default_policy_3 policy_3;
};
template<class T>
struct policy_1_is:virtual default_polices
{
    typedef T policy_1;
};
template<class T>
struct policy_2_is:virtual default_polices
{
    typedef T policy_2;
};
template<class T>
struct policy_3_is:virtual default_polices
{
    typedef T policy_3;
};
template<int ID>
struct default_polices_arg:virtual default_polices
{};

template
    <class Policy_1
    ,class Policy_2
    ,class Policy_3
    >
struct polices_discriminator
    :Policy_1
    ,Policy_2
    ,Policy_3
{};

template
    <class Policy_1=default_polices_arg<1>
    ,class Policy_2=default_polices_arg<2>
    ,class Policy_3=default_polices_arg<3>
    >
struct some_class
{
    typedef polices_discriminator
        <Policy_1
        ,Policy_2
        ,Policy_3
        > policy;
    typedef typename policy::policy_1 policy_1;
    typedef typename policy::policy_2 policy_2;
    typedef typename policy::policy_3 policy_3;
};
template<class T>
void polices_print()
{
    std::cout<<typeid(typename T::policy_1).name()<<std::endl;
    std::cout<<typeid(typename T::policy_2).name()<<std::endl;
    std::cout<<typeid(typename T::policy_3).name()<<std::endl;
    std::cout<<std::endl;
}
int main()
{
    polices_print<some_class<> >();
    polices_print<some_class<policy_1_is<int>, policy_3_is<char> > >();
    return 0;
}

вывод
struct default_policy_1
struct default_policy_2
struct default_policy_3

int
struct default_policy_2
char

Press any key to continue
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Как задать некоторые параметры шаблона?
От: Кодт Россия  
Дата: 26.06.04 19:42
Оценка: 10 (1)
Здравствуйте, What, Вы писали:

W>Я пишу "библиотечный" класс, с N = 5 стратегиями.

W>
W>template <typename T1, typename T2, ... , typename TN> class CMyClass;
W>

W>В большинстве случаев используется один и тот же набор параметров.
W>Пользователи класса хотят иметь возможность задавать "отклонения" от этого набора.
W>Например, задать параметр T3, а остальные оставить по умолчанию и даже не задумываться об их значении.
W>Как это реализовать?

Пришла в голову дурка: сделать именованные параметры шаблонов.
/// в клиентском коде
typedef YourTemplateClass<
    boost::mpl::list<
        std::pair< second_type_tag, TheSecond >,
        std::pair< first_type_tag, TheFirst >,
        . . . > > YourType;

/// в коде шаблона

// у тэгов - осмысленные имена
struct first_type_tag {};
struct second_type_tag {};
struct third_type_tag {};

template<NamedArgs>
class YourTemplateClass
{
    typedef typename mpl_search_key<NamedArgs, first_type_tag, DefaultFirst> first_type;
    typedef typename mpl_search_key<NamedArgs, second_type_tag, DefaultSecond> third_type;
    typedef typename mpl_search_key<NamedArgs, third_type_tag, DefaultThird> third_type;
    . . .
};

Я не монстр в программировании с boost::mpl, но полагаю, что там будет не очень сложно.
Нужно использовать boost::mpl::find_if с рукодельным предикатом.
... << RSDN@Home 1.1.2 stable >>
Перекуём баги на фичи!
Re: Как задать некоторые параметры шаблона?
От: MaximE Великобритания  
Дата: 26.06.04 22:40
Оценка: 10 (1)
What wrote:

[]

> Может есть другие идеи, комментарии, критика?

> Основным критерием является удобство использования класса пользователями.

Использовать технику "именованные шаблонные параметры" (в google как "named template parameters"). В первый раз я эту идею увидел в "белых бумагах" к boost::iterator_adaptor<>, в исходниках можно посмотреть реализацию.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 beta
Re[2]: Как задать некоторые параметры шаблона?
От: What Беларусь  
Дата: 27.06.04 12:59
Оценка: 36 (1)
Здравствуйте, MaximE, Вы писали:

ME>Использовать технику "именованные шаблонные параметры" (в google как "named template parameters"). В первый раз я эту идею увидел в "белых бумагах" к boost::iterator_adaptor<>, в исходниках можно посмотреть реализацию.


Я нашёл эту технику в boost mailing list.
Однако, судя по исходникам boost 1.31.0, в boost::iterator_adaptor она не используется.
Вместо этого они заводят структуру
 struct use_default;

А для выбора стратегии используют
mpl::apply_if<
            is_same<T, use_default>
          , DefaultNullaryFn
          , mpl::identity<T> >

Пример использования:
typedef boost::iterator_adaptor<
        node_iter<Value>, Value*, boost::use_default, boost::forward_traversal_tag
             > super_t;


P.S.
ИМХО, использование use_default намного очевиднее, чем named template parameters
В любом случае, спасибо за помощь.
... << RSDN@Home 1.1.3 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.