2017-02-20 46 views
-1

я следующий код:Рефакторинг тег диспетчерские структуры

#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 

Он сейчас работает. Не совсем уверен, если этот код теперь согласуется с концепцией отправки тега

+0

'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' во время выполнения. Тогда в чем смысл отправки меток, который является методом метапрограммирования во время компиляции? Вы говорите, что отправка тега не подлежит обсуждению - но почему? Какую цель, по вашему мнению, он здесь служит? –

+0

Спасибо, это была моя точка. Чтобы получить ответ, полезно ли использование меток в этом конкретном примере: Нет! потому что проверка выполняется ли y == 0 во время выполнения – FloriHe

+1

Отправка тега для выбора алгоритма во время компиляции на основе некоторой временной характеристики во время компиляции (например, 'std :: distance' будет реализована по-разному для случайных событий, итераторы доступа к итераторам вперед). Я не вижу, как это применимо к этому случаю. –

ответ

0

Я думаю, что вам лучше проверить мнимую часть во время выполнения, а не компилировать время. Ниже приведен пример, который использует std::complex

#include <complex> 
#include <iostream> 
#include <limits> 
#include <sstream> 

template<class T> 
auto print(std::complex<T> const& c) 
{ 
    std::stringstream sstr; 
    if (std::abs(c.imag()) < std::numeric_limits<T>::epsilon()) { 
     sstr << c.real();  
    } else { 
     sstr << c;  
    } 
    return sstr.str(); 
} 

int main() 
{ 
    auto const c1 = std::complex{1.0}; 
    auto const c2 = std::complex{2.0, 3.0}; 

    std::cout << print(c1) << "\n"; // prints: 1 
    std::cout << print(c2) << "\n"; // prints: (2, 3) 
} 

Live Example

+0

Да, конечно, я знаю, что есть 1000 решений, которые решают этот конкретный пример намного лучше. Но это не вопрос моего вопроса. Я как-то сталкиваюсь с этой проблемой с моими последними вопросами здесь, в C++. Я не очень заинтересован в том, чтобы получить какое-либо решение для моего примера, но решение, ограниченное определенной концепцией, как правильно указал Игорь Тандетник. Я отправляю такие вопросы, чтобы получить обратную связь, правильно ли я понял концепцию, и если конкретная концепция может быть применена к конкретному примеру или нет. – FloriHe

 Смежные вопросы

  • Нет связанных вопросов^_^