я следующий код:Рефакторинг тег диспетчерские структуры
#include <iostream>
#include <cassert>
#include <utility>
struct real_type {
struct real_category{};
typedef real_category num_category;
};
struct imag_type: public real_type {
struct imag_category{};
typedef imag_category num_category;
};
template<class number_type>
struct number_traits {
typedef typename number_type::num_category num_category;
};
void print_num(double x, double y, typename real_type::num_category) {
assert(y==0);
std::cout<<"real num - x: "<<x<<std::endl;
}
void print_num(double x, double y, typename imag_type::num_category) {
std::cout<<"imag num - x: "<<x<<", y: "<<y<<std::endl;
}
template<int Y=0, typename num_type = typename std::conditional<Y==0, real_type, imag_type>::type >
void print_num(double x) {
typename number_traits<num_type>::num_category num_category;
print_num(x, Y, num_category);
}
int main() {
print_num(1);
print_num<3>(2);
return 0;
}
С выходом:
real num - x: 1
imag num - x: 2, y: 3
Я не очень доволен поведением этого кода. Как можно видеть, меня ограничивают мнимые значения целыми числами. Также я должен назвать мнимый вариант print_num с конечным <>
, который тоже не изящный.
Причиной этой конструкции было то, что для того, чтобы вывести правильный тег категории, мне пришлось проверить значение Y
. Но эта проверка возможна только в списке параметров шаблона.
Так что мой вопрос:. Можно ли, сохраняя при этом тег-диспетчерской структуру (т.е. сохранение функции void print_num(..., typename real_type::num_category)
и void print_num(..., typename imag_type::num_category)
, как они, чтобы определить функцию диспетчерскую как void print_num(double x, double y=0)
Это будет означать(), чтобы как-то выводит? правильно num_category, проверяя, если y==0
или нет.
Я знаю, что я мог бы просто решить эту проблему, проверив это с if(y==0)\*then call print_num with real_category tag*\else \*call with imag_category tag*\
в функции void print_num(double x, double y=0)
. Это позволит сделать класс number_traits устаревшее (который я не хочу). Т.е. я бы как это сделать в списке параметров шаблона. Возможно ли это? Я думаю, что нет (?)
обновление:
Исходя из ответов, которые я переписал код:
#include <iostream>
#include <cassert>
#include <utility>
struct real_type {
struct real_category{};
typedef real_category num_category;
struct real_number{ double x; };
typedef real_number num;
num num_x;
};
struct imag_type: public real_type {
struct imag_category{};
typedef imag_category num_category;
struct imag_number{ double x; double y; };
typedef imag_number num;
num num_xy;
};
template<class number_type>
struct number_traits {
typedef typename number_type::num_category num_category;
};
void print_num(real_type r, typename real_type::num_category) {
std::cout<<"real num - x: "<<r.num_x.x<<std::endl;
}
void print_num(imag_type i, typename imag_type::num_category) {
std::cout<<"imag num - x: "<<i.num_xy.x<<", y: "<<i.num_xy.y<<std::endl;
}
template<typename num_type>
void print_num(num_type i) {
typename number_traits<num_type>::num_category num_category;
print_num(i, num_category);
}
int main() {
real_type r_type;
r_type.num_x.x = 1.1;
imag_type i_type;
i_type.num_xy.x = 2.1;
i_type.num_xy.y = 3.2;
print_num(r_type);
print_num(i_type);
return 0;
}
Выход:
real num - x: 1.1
imag num - x: 2.1, y: 3.2
Он сейчас работает. Не совсем уверен, если этот код теперь согласуется с концепцией отправки тега
'print_num (двойной х, дважды у = 0) {если (у == 0) print_num (х, у, real_type :: num_category {}); else print_num (x, y, imag_type :: num_category {}); '. Хотя я не вижу смысла. С сигнатурой типа 'print_num (double x, double y = 0)', вы явно ожидаете проверить 'y' во время выполнения. Тогда в чем смысл отправки меток, который является методом метапрограммирования во время компиляции? Вы говорите, что отправка тега не подлежит обсуждению - но почему? Какую цель, по вашему мнению, он здесь служит? –
Спасибо, это была моя точка. Чтобы получить ответ, полезно ли использование меток в этом конкретном примере: Нет! потому что проверка выполняется ли y == 0 во время выполнения – FloriHe
Отправка тега для выбора алгоритма во время компиляции на основе некоторой временной характеристики во время компиляции (например, 'std :: distance' будет реализована по-разному для случайных событий, итераторы доступа к итераторам вперед). Я не вижу, как это применимо к этому случаю. –