LINUX.ORG.RU

Шаблонная магия С++. Как указать один из дефолтных параметров?

 ,


0

6

Доброго дня и новго года.

Камарады, есть вот такой вот, например, код

template <typename K, typename V, 
          typename VTrait = traits::simple<V>,
          typename SizeTrait = traits::default_size,
          typename MutexType = std::mutex
          >
class test {....};

То есть некоторый контейнер с шаблонными параметрами, часть из которых имеют значения по-умолчанию.

Теперь, если я хочу изменить только, например, mutex, то мне придется написать

template <typename K, typename V, typename MutexType>
using my_test = test<K, V, traits::simple<V>, traits::default_size, MutexType>;
Проблема в том, что мне нужно явно указать все параметры по-умолчанию, которые следуют до mutex, что не есть хорошо, поскольку само объявление класса test может поменяться и я хотел бы, чтоб во всех using оно так же поменялось.

Есть какой-то шаблонно-магический способ это решить?

Спасибо.

cast eao197, например...

Рисуй трейты на все возможные чихи (по ходу дела) с явной специализацией и тестай их на принадлежность к разным типам или тупо true/false параметры проверяй, если чихов не больше двух, в явных же специализациях класса test, например :)

slackwarrior ★★★★★ ()

По мотивам http://stackoverflow.com/a/15418928

#include <tuple>

template<template<typename...> class T, typename>
struct instantiate_with_arg_pack { };
template< template<typename...> class T
        , template<typename...> class U
        , typename... Ts>
struct instantiate_with_arg_pack<T, U<Ts...>>
{
    using type = T<Ts...>;
};

template<class T>
using to_tuple = typename instantiate_with_arg_pack<std::tuple, T>::type;

Это то, чем мы будем пользоваться. А пользоваться будем так:

template <typename K, typename V, typename MutexType, typename Tuple=to_tuple<test<K,V>> >
using my_test = test<K, V, std::tuple_element_t<2,Tuple>, std::tuple_element_t<3,Tuple>, MutexType>;

Проверка (http://ideone.com/BTf1MG)

template<typename T = int, typename U = double> struct exampl {};
 
template<typename T> struct TD;
 
int main()
{
    using Tuple = to_tuple<exampl<>>;
    TD< exampl<std::tuple_element_t<1, Tuple>, std::tuple_element_t<0, Tuple>> > td; // should swap default template parameters
}
prog.cpp:28:82: error: aggregate 'TD<exampl<double, int> > td' has incomplete type and cannot be defined
Получилось.

utf8nowhere ★★ ()

Можно сделать трейт для трейтов :)

template<typename K, typename V>
struct container_traits {
  using VTraits = traits::simple<V>;
  using SizeTrait = traits::default_size;
  using Mutex = std::mutex;
};

template<typename K, typename V, typename Traits = container_traits<K, V> >
class test { ... };
После чего можно будет уточнить только отдельные свойства:
template<typename K, typename V>
struct my_traits : public containter_traits<K, V> {
  using Mutex = my_mega_mutex;
};

template<typename K, typename V>
using my_test = test<K, V, my_traits<K, V> >;

Насколько это будет удобно — хз.

eao197 ★★★★★ ()
Ответ на: комментарий от utf8nowhere

Вот, нашёл ссылку, которую читал раньше и не мог найти сейчас: http://www.pdimov.com/cpp2/simple_cxx11_metaprogramming.html

На StackOverflow я наткнулся ища про нечто, реализующее mp_rename из вышеприведённой ссылки. mp_rename мне нравится больше

template<class A, template<class...> class B>
struct mp_rename_impl;
template<template<class...> class A, class... T, template<class...> class B>
struct mp_rename_impl<A<T...>, B>
{
    using type = B<T...>;
};
template<class A, template<class...> class B>
using mp_rename = typename mp_rename_impl<A, B>::type;

С ним должно быть так:

template <typename K, typename V, typename MutexType, typename Tuple=mp_rename<test<K,V>,std::tuple> >
using my_test = test<K, V, std::tuple_element_t<2,Tuple>, std::tuple_element_t<3,Tuple>, MutexType>;

utf8nowhere ★★ ()

Есть какой-то шаблонно-магический способ это решить?
cast eao197, например...

Кастуй уже Александреску, чё уж там :-) Только он владеет этим тайным искусством :-)

anonymous ()
Ответ на: комментарий от anonymous

Кастуй уже Александреску, чё уж там :-) Только он владеет этим тайным искусством :-)

Он просил передать, что вы все его задолбали, и предлагает переписать всё на D.

DELIRIUM ★★★★★ ()
Ответ на: комментарий от DELIRIUM

Он просил передать, что вы все его задолбали, и предлагает переписать всё на D.

Рассказывал всем про «Современное проектирование на C++», книгу целую написал, целую библиотеку Loki на C++ написал (это которая вся в шаблонах и там и здесь), а теперь предлагает писать на D :-) Лол :-) Интересно, почему? :-)

anonymous ()

utf8nowhere

годно. Наверное так и сделаю, ибо лучшего пока не вижу.

eao197

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

Всем спасибо. =)

seryoga ()
Ответ на: комментарий от eao197

«шо то х*ня, шо это х*ня» (с) Эскобар — ну, в общем выбор мсьям понимающим толк обычно предлагается только среди сортов субстанций:)

slackwarrior ★★★★★ ()
namespace somelocal
{
   class default_A {};
   class default_B {};
   class default_C {};

   template<typename A,typename B, typename C>
   class test
   {
      typedef std::conditional<is_void<A>, default_A, A>::type Type1;
      typedef std::conditional<is_void<B>, default_B, B>::type Type2;
      typedef std::conditional<is_void<C>, default_C, C>::type Type3;
   };
}

somelocal::test<void,type1,void> v;
pathfinder ★★★ ()
Ответ на: комментарий от utf8nowhere

Косметические улучшения

template<class A, template<class...> class B>
struct mp_rename_impl;
template<template<class...> class A, class... T, template<class...> class B>
struct mp_rename_impl<A<T...>, B>
{
    using type = B<T...>;
};
template<class A, template<class...> class B>
using mp_rename = typename mp_rename_impl<A, B>::type;

#include <tuple>

template<typename T> struct template_arg_getter
{
    using _tuple = mp_rename<T,std::tuple>;
    template<size_t N>
    using get_nth = std::tuple_element_t<N, _tuple>;
};


template <typename K, typename V, 
          typename VTrait = long,
          typename SizeTrait = short,
          typename MutexType = void>
class test {};

template< typename K, typename V, typename MutexType
        , template<size_t> class default_arg=template_arg_getter<test<K,V>>::template get_nth >
using my_test = test<K, V, default_arg<2>, default_arg<3>, MutexType>;


template<class T> struct TD;
int main()
{
    TD<my_test<int,double,char>> td;
}

Вроде работает:

prog.cc: In function 'int main()':
prog.cc:36:34: error: aggregate 'TD<test<int, double, long int, short int, char> > td' has incomplete type and cannot be defined
     TD<my_test<int,double,char>> td;

utf8nowhere ★★ ()
Ответ на: комментарий от pathfinder

Хорошее решение. Только is_void_v. И вообще я бы наворотил чего-нибудь такого:

#include <type_traits>

enum class default_arg {};
template<typename T> struct is_default : std::is_same<default_arg, T> {};
template<typename T> constexpr bool is_default_v = is_default<T>::value;
template<typename T, typename U>
using if_default = std::conditional_t<is_default_v<T>, U, T>;

template<typename T, typename _U = default_arg>
class ass { public: using U = if_default<_U, int>; };

int main() {
    static_assert(std::is_same_v<int,  ass<void>::U>);
    static_assert(std::is_same_v<char, ass<void,char>::U>);
}

utf8nowhere ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.