使用 boost::variant 并获取泛型返回类型

Using boost::variant and getting a generic return type

本文关键字:泛型 返回类型 获取 variant boost 使用      更新时间:2023-10-16

我正在寻找如何重构这段代码的想法或关于我是否过度思考它的意见。请考虑以下boost::variant

using Pattern = boost::variant<std::regex, MyOwnClass>;  

现在这是我想做什么的想法:

Pattern pattern;
// do some stuff...
// see if the pattern matches some data
PatternVisitor pvisitor(dataBegin, dataEnd);
if (boost::apply_visitor(pvisitor, pattern))
{
    // want to use pvisitor.matches generically inside here 
    // regardless of what variant pattern is
    for (auto idx = 0; idx < pvisitor.matches.size(); idx)
    {
        // now use the match
        std::string strMatch(pvisitor.matches[idx].first, pvisitor.matches[idx].second);
        std::cout << strMatch << 'n';
    }
}

那么,如何定义PatternVisitor呢?我从实现std::regex部分开始,并提出了类似的东西:

struct PatternVisitor : public boost::static_visitor<bool>
{
    PatternVisitor(const char* sBegin, const char* sEnd)
        : searchBegin(sBegin), searchEnd(sEnd)
    {
    }
    bool operator()(const std::regex& regexp) 
    {
        return std::regex_search(searchBegin, searchEnd, regmatches, regexp, std::regex_constants::match_continuous);
    }
    bool operator()(const MyOwnClass& myClass)
    {
        // save this implementation for later, return true for now
        return true;
    }
    const char* searchBegin;
    const char* searchEnd;    
    std::cmatch matches;
};

这很好,但是...MyOwnClass呢?我的第一个想法是我可以自己填充std::cmatch但这似乎是不可能的,也不是一个好主意。因此,我当前的解决方案是这样的:

struct PatternVisitor : public boost::static_visitor<bool>
{
    PatternVisitor(const char* sBegin, const char* sEnd)
        : searchBegin(sBegin), searchEnd(sEnd)
    {
    }
    bool operator()(const std::regex& regexp) 
    {
        std::cmatch regmatches;
        if (std::regex_search(searchBegin, searchEnd, regmatches, regexp, std::regex_constants::match_continuous))
        {
            for (const auto& m : regmatches)
            {
                matches.push_back(std::make_pair(m.first, m.second));
            }
        }
        return !matches.empty();
    }
    bool operator()(const MyOwnClass& format)
    {
        // now I can just populate matches as needed
        return true;
    }
    const char* searchBegin;
    const char* searchEnd;    
    std::vector<std::pair<const char*, const char*>> matches;
};

虽然这有效,但我不喜欢将我需要的数据从regmatches复制到另一个向量中。

能够以通用方式使用生成的匹配项的同时重构这一点的好方法是什么?

您可以在访问者中应用您的函数,例如:

struct PatternVisitor : public boost::static_visitor<bool>
{
    PatternVisitor(const char* sBegin,
                   const char* sEnd,
                   std::function<void (const char*, const char*)> f)
        : searchBegin(sBegin), searchEnd(sEnd), f(f)
    {
    }
    bool operator()(const std::regex& regexp) 
    {
        std::cmatch regmatches;
        if (std::regex_search(searchBegin,
                              searchEnd,
                              regmatches,
                              regexp,
                              std::regex_constants::match_continuous)) {
            for (const auto& m : regmatches) {
                f(m.first, m.second);
            }
            return true;
        }
        return false;
    }
    bool operator()(const MyOwnClass& myClass)
    {
        // save this implementation for later, return true for now
        return true;
    }
    const char* searchBegin;
    const char* searchEnd;    
    std::function<void (const char*, const char*)> f;
};

然后

Pattern pattern = /*...*/;
PatternVisitor pvisitor(dataBegin, dataEnd, [](const char* beg, const char* end)
    {
        std::string strMatch(beg, end);
        std::cout << strMatch << 'n';
    });
boost::apply_visitor(pvisitor, pattern);