首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >派生自“`boost::static”以删除代码重复

派生自“`boost::static”以删除代码重复
EN

Stack Overflow用户
提问于 2017-04-06 10:56:33
回答 1查看 246关注 0票数 1

在我的一个项目中,我过度使用了boost-variant。在某种程度上,我超过了boost-variant的最大模板参数数(20)。因此,我通过像链接列表一样将几个boost-variant类型链接在一起得出了以下解决方案。

代码语言:javascript
复制
#include <boost/variant.hpp>
#include <iostream>

template<int T> struct A {
    const int value = T;
};

typedef boost::variant<
    A<20>,A<21>,A<22>,A<23>,A<24>,A<25>,A<26>,A<27>,A<28>,A<29>,A<30>,A<31>,A<32>,A<33>,A<34>,A<35>,A<36>,A<37>,A<38>,A<39>
> NextVar;

typedef boost::variant<
    A<1>,A<2>,A<3>,A<4>,A<5>,A<6>,A<7>,A<8>,A<9>,A<10>,A<11>,A<12>,A<13>,A<14>,A<15>,A<16>,A<17>,A<18>,A<19>,NextVar
> TVar;

struct PrintVisitor : public boost::static_visitor<std::string> {
    result_type operator()(const NextVar& n) {
        return n.apply_visitor(*this);
    }

    template<int T>
    result_type operator()(const A<T>& a)  {
        return std::to_string(a.value);
    }
};

struct IntVisitor : public boost::static_visitor<int> {
    result_type operator()(const NextVar& n) {
        return n.apply_visitor(*this);
    }

    template<int T>
    result_type operator()(const A<T>& a) {
        return a.value;
    }
};

template<int I>
struct AddVisitor : public boost::static_visitor<int> {
    result_type operator()(const NextVar& n) {
        return n.apply_visitor(*this);
    }

    template<int T>
    result_type operator()(const A<T>& a) {
        return a.value+I;
    }
};

int main(int argc, char **args) {
    TVar x = A<35>(); 
    PrintVisitor v1;
    std::cout << x.apply_visitor(v1) << std::endl;
    IntVisitor v2;
    std::cout << x.apply_visitor(v2) << std::endl;
    AddVisitor<10> v3;
    std::cout << x.apply_visitor(v3) << std::endl;
}

我真的很惊讶这个办法能很好地解决我的问题。但还是有一粒盐。对于每一位访客,我必须包括以下内容:

代码语言:javascript
复制
result_type operator()(const NextVar& n) {
    return n.apply_visitor(*this);
}

这似乎是一种不必要的代码复制。更糟的是,如果我需要60种甚至更多的boost-variant类型。我的尝试是为所有访问者定义一个公共基类:

代码语言:javascript
复制
template<typename T>
struct BaseVisitor : public boost::static_visitor<T> {
    result_type operator()(const NextVar& n) {
        return n.apply_visitor(*this);
    }
};

我认为,从BaseVisitor派生而来,如下图所示,可以解决这个问题:

代码语言:javascript
复制
struct PrintVisitor : public BaseVisitor<std::string> {
    template<int T>
    result_type operator()(const A<T>& a)  {
        return std::to_string(a.value);
    }
};

但是编译器却抱怨:

代码语言:javascript
复制
template-argument for "const A<T> &" could not be derived from "T19" 

对于这类问题,最接近的解决办法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-06 12:09:40

首先,您可以简单地增加由BOOST_MPL_LIMIT_LIST_SIZE确定的20的限制。

关于您的代码:即使它编译了,BaseVisitor::operator()也会产生无限的递归,因为那时*this被认为是BaseVisitor。

为了避免这种情况,您可以使用CRTP来拥有好的derived()

代码语言:javascript
复制
template<class Derived, typename T>
struct BaseVisitor : public boost::static_visitor<T> {
    using typename boost::static_visitor<T>::result_type;

    Derived & derived() { return static_cast<Derived &>(*this); } 

    result_type operator()(const NextVar& n) {
        return n.apply_visitor( derived() );
    }
};

然后将相同的operator()引入派生类(以及模板类所需的result_type )的作用域(否则由新的类隐藏)。

演示

无别名

正如注释中所说,别名必须写在每个派生类中。为了摆脱它,我们可以在基类中将两个operator()在同一个级别上收集起来,并将派生函数命名不同(这里是visit):

代码语言:javascript
复制
template<class Derived, typename T>
struct BaseVisitor : public boost::static_visitor<T> {
    using typename boost::static_visitor<T>::result_type;

    Derived & derived() { return static_cast<Derived &>(*this); } 

    result_type operator()(const NextVar& n) {
        return n.apply_visitor( derived() );
    }
    template<int I>
    result_type operator()(const A<I>& a)  {
        return derived().visit(a);
    }
};

留给我们:

代码语言:javascript
复制
struct PrintVisitor : public BaseVisitor<PrintVisitor, std::string> {
    template<int I>
    std::string visit(const A<I>& a)  {
        return std::to_string(a.value);
    }
};

演示

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43253156

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档