Я пишу "библиотечный" класс, с 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 >>
Здравствуйте, 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 >>
Здравствуйте, 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 >>
What wrote:
[]
> Может есть другие идеи, комментарии, критика?
> Основным критерием является удобство использования класса пользователями.
Использовать технику "именованные шаблонные параметры" (в google как "named template parameters"). В первый раз я эту идею увидел в "белых бумагах" к boost::iterator_adaptor<>, в исходниках можно посмотреть реализацию.
--
Maxim YegorushkinPosted via RSDN NNTP Server 1.9 beta
Здравствуйте, 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 >>