gpt4 book ai didi

c++ - 从 `boost::static-visitor` 派生以删除代码重复

转载 作者:行者123 更新时间:2023-11-30 03:33:02 26 4
gpt4 key购买 nike

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

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

我真的很惊讶这个变通办法解决了我的问题。仍然有一粒盐。我必须为每位访问者添加以下行:

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

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

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

我认为,如下所示从 BaseVisitor 派生可以解决问题:

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

但是编译器却提示:

template-argument for "const A<T> &" could not be derived from "T19" 

对于此类问题,最接近的解决方法可能是什么?

最佳答案

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

关于您的代码:即使编译通过,BaseVisitor::operator() 也会进行无限递归,因为此时 *this 被视为 BaseVisitor。< br/>为避免这种情况,您可以使用 CRTP 代替良好的 derived():

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)的范围(否则被新的隐藏)。

DEMO

没有别名

正如评论中所说,别名必须写在每个派生类中。为了摆脱它,我们可以将两个 operator() 集中在基类中的同一级别,并对派生函数进行不同的命名(访问 此处):

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

留给我们:

struct PrintVisitor : public BaseVisitor<PrintVisitor, std::string> {
template<int I>
std::string visit(const A<I>& a) {
return std::to_string(a.value);
}
};

DEMO

关于c++ - 从 `boost::static-visitor` 派生以删除代码重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43253156/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com