重构标签调度结构

时间:2017-02-20 13:37:25

标签: c++ c++11 templates tags

我有以下代码:

$(".track_it").click(function () {
console.log($(this).data("location"));
});

输出:

#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的虚构变体,这也不是优雅的。

这种结构的原因是,为了推断出正确的类别标签,我必须检查<>的值。但是这种检查只能在模板参数列表中进行。

所以我的问题是:是否有可能在保持此标记调度结构(即保持函数Yvoid 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*\进行检查来解决此问题。这会使number_traits类过时(我不想要)。即我想在模板参数列表中做出这个决定。这可能吗?我想不是(?)

更新

基于答案我重写了代码:

void print_num(double x, double y=0)

输出:

#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;
}

它现在正在工作。如果此代码现在与tag-dispatch概念一致,则不完全确定

1 个答案:

答案 0 :(得分: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