2017-02-20 41 views
-1

我有以下代碼:重構tag分派結構

#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)的調度功能這意味着()以某種方式演繹?通過檢查y==0或不正確num_category。

我知道我可以只通過與void print_num(double x, double y=0)功能if(y==0)\*then call print_num with real_category tag*\else \*call with imag_category tag*\選中此解決這個問題。這將使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一個例子(雙X,雙Y = 0){如果(Y == 0)print_num(X,Y,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'對於random-訪問迭代器vs前向迭代器)。我不明白它如何能有效地應用於這種情況。 –

回答

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++下。我對我的例子沒有太大的興趣,不能解決我的問題,但是正如Igor Tandetnik正確指出的那樣,解決方案受限於某個特定的概念。我發佈了這些類型的問題以獲得反饋,以瞭解我是否正確理解某個概念,以及某個特定概念是否可以應用於特定示例。 – FloriHe