Comments 11
Здорово, но я могу то же самое без буста и в 30 строк (проверка правда не уместилась :)
#include <string>
#include <iostream>
#define static_type(name) static constexpr const char* type_name() { return name; }
struct disabled { static_type("disabled"); };
struct deferred { static_type("deferred"); };
struct deadline { static_type("deadline"); };
template<typename Expected, typename...T>
struct match { typedef disabled type; };
template <typename Expected, typename...T>
struct match<Expected, Expected, T...> { typedef Expected type; };
template <typename Expected, typename Actual, typename...T>
struct match<Expected, Actual, T...> { typedef typename match<Expected, T...>::type type; };
template<class T, typename... Plugins>
struct container
{
typedef typename match<deferred, Plugins...>::type deferred_;
typedef typename match<deadline, Plugins...>::type deadline_;
static std::string type_name()
{
return std::string("container<") + deferred_::type_name() + ", " + deadline_::type_name() + ">";
}
};
int main()
{
using namespace std;
cout << container<int>::type_name() << std::endl;
cout << container<int, deadline>::type_name() << std::endl;
cout << container<int, deferred>::type_name() << std::endl;
cout << container<int, deferred, deadline>::type_name() << std::endl;
cout << container<int, deadline, deferred>::type_name() << std::endl;
}
+7
Извините, но я немножко не понял концепцию. Обычно, ведь, каждый параметр шаблона, в таких случаях, отвечает за некоторое свойство(которое имеет ряд значений). Например,
А чтобы всё работало в случае с произвольным порядком нужно иметь «договорённость»: это «свойство» (параметр шаблона) имеет ряд конкретных значений(типов): 1, 2, 3. Другое свойство имеет другой набор: 4, 5, 6. Причём значения не должны совпадать(т.е. типы должны не совпадать, кроме как «значения по-умолчанию»). Я правильно понимаю? А это не усложняет всё? Не ограничивает?
UPD: если я правильно понял, то как раз это Вы и написали:
boost::transform_iterator
:template <class UnaryFunction,
class Iterator,
class Reference = use_default,
class Value = use_default>
class transform_iterator
Reference
отвечает за член класса reference
и, выставляя Reference
, мы управляем «свойством» reference
и т.д. И порядок имеет значение — чтобы выставить reference
, мы задаём его значение 3м аргументом. Как Вы и сказали:Но мы прекрасно понимаем, что как только мы поменяли два параметр у нас получится совершенно не то чего мы ожидали
А чтобы всё работало в случае с произвольным порядком нужно иметь «договорённость»: это «свойство» (параметр шаблона) имеет ряд конкретных значений(типов): 1, 2, 3. Другое свойство имеет другой набор: 4, 5, 6. Причём значения не должны совпадать(т.е. типы должны не совпадать, кроме как «значения по-умолчанию»). Я правильно понимаю? А это не усложняет всё? Не ограничивает?
UPD: если я правильно понял, то как раз это Вы и написали:
Способ который я хочу показать не позволяет специализировать шаблон произвольным типом.
0
Да, как раз так. Этот способ имеет существунное ограниение, и применим только в узком ряде задач, коий у меня возник и я решил описать.
0
На самом деле это ограничение легко обходится, достаточно только заменить параметры с типов на шаблоны.
Тогда вместо
получится
А использоваться это будет так:
В итоге получается как-то так
Тогда вместо
struct deferred
получится
template <typename T>
struct deferred_tag { typedef T type; };
А использоваться это будет так:
cout << container<int, deferred_tag<deferred_type_2>, deadline_tag<deadline_type>>::type_name() << std::endl;
В итоге получается как-то так
Посмотреть код
#include <string>
#include <iostream>
#define static_type(name) static constexpr const char* type_name() { return name; }
struct disabled_type { static_type("disabled"); };
struct deferred_type { static_type("deferred"); };
struct deferred_type_2 { static_type("deferred2!"); };
struct deadline_type { static_type("deadline"); };
struct deadline_type_2 { static_type("deadline2!"); };
template <typename T = deferred_type>
struct deferred_tag { typedef T type; };
template <typename T = deadline_type>
struct deadline_tag {typedef T type; };
template<template <class> class Expected, typename...T>
struct match { typedef disabled_type type; };
template <typename V, template <class> class Expected, typename...T>
struct match<Expected, Expected<V>, T...> { typedef typename Expected<V>::type type; };
template <template <class> class Expected, typename Actual, typename...T>
struct match<Expected, Actual, T...> { typedef typename match<Expected, T...>::type type; };
template<class T, typename... Plugins>
struct container
{
typedef typename match<deferred_tag, Plugins...>::type deferred_;
typedef typename match<deadline_tag, Plugins...>::type deadline_;
static std::string type_name()
{
return std::string("container<") + deferred_::type_name() + ", " + deadline_::type_name() + ">";
}
};
int main()
{
using namespace std;
cout << container<int>::type_name() << std::endl;
cout << container<int, deadline_tag<deadline_type>>::type_name() << std::endl;
cout << container<int, deferred_tag<deferred_type>>::type_name() << std::endl;
cout << container<int, deferred_tag<deferred_type>, deadline_tag<deadline_type>>::type_name() << std::endl;
cout << container<int, deadline_tag<deadline_type>, deferred_tag<deferred_type>>::type_name() << std::endl;
cout << container<int, deadline_tag<deadline_type_2>, deferred_tag<deferred_type_2>>::type_name() << std::endl;
cout << container<int, deadline_tag<deadline_type_2>>::type_name() << std::endl;
cout << container<int, deferred_tag<deferred_type_2>, deadline_tag<>>::type_name() << std::endl;
}
+1
Могу предложить способ с использованием старых добрых enum'ов. Хорош тем, что порядок действительно неважен:
container<T, DEADLINE|DEFERRED>
и container<T, DEFERRED|DEADLINE>
дают один и тот же тип (в отличие от приведенного в статье подхода).#include <iostream>
#define static_type(name) static constexpr const char* type_name() { return name; }
struct disabled { static_type("disabled"); };
struct deferred { static_type("deferred"); };
struct deadline { static_type("deadline"); };
enum {
DEFERRED = 1,
DEADLINE = 2,
MAX_POWER_OF_TWO = 4
};
template<int V, class A, class B>
struct type_selector {
typedef B type;
};
template<class A, class B>
struct type_selector<0, A, B> {
typedef A type;
};
template<class T, int Plugins = 0>
struct container
{
static_assert(Plugins >= 0 && Plugins < MAX_POWER_OF_TWO, "Invalid flags");
typedef typename type_selector<Plugins & DEFERRED, disabled, deferred>::type
deferred_type;
typedef typename type_selector<Plugins & DEADLINE, disabled, deadline>::type
deadline_type;
static std::string type_name() {
return std::string("container<") + deferred_type::type_name()
+ ", " + deadline_type::type_name() + ">";
}
};
int main() {
using namespace std;
cout << container<int>::type_name() << std::endl;
cout << container<int, DEADLINE>::type_name() << std::endl;
cout << container<int, DEFERRED>::type_name() << std::endl;
cout << container<int, DEFERRED | DEADLINE>::type_name() << std::endl;
//cout << container<int, 6>::type_name() << std::endl; //Ошибка компиляции
return 0;
}
+5
Boost.Parameter
0
42
+1
Нашел пример как сделать именнованые шаблонные параметры, это собстно именно то чего хотелось достич в идеале
stackoverflow.com/questions/11251242/boost-parameter-named-template-argument-in-combination-with-crtp
Так как можно указывать парметры в произвольном порядке и числе, а так же нет привязки к конкретным типам, и спокойно можно использовать новые (определнные пользователем) без какой либо модификации базового кода.
stackoverflow.com/questions/11251242/boost-parameter-named-template-argument-in-combination-with-crtp
Так как можно указывать парметры в произвольном порядке и числе, а так же нет привязки к конкретным типам, и спокойно можно использовать новые (определнные пользователем) без какой либо модификации базового кода.
0
Sign up to leave a comment.
Произвольный порядок списка инициализации шаблона