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

时间:2017-10-17 16:33:44

标签: c++ templates boost-variant

我正在寻找关于如何重构这些代码或关于我是否过度思考它的意见的想法。请考虑以下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复制到另一个向量中。

在能够以通用方式使用结果匹配的同时重构这个的好方法是什么?

1 个答案:

答案 0 :(得分:1)

您可以在访问者中应用您的功能,例如:

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