boost::variant 将 static_visitor 应用于某些类型

Posted

技术标签:

【中文标题】boost::variant 将 static_visitor 应用于某些类型【英文标题】:boost::variant apply static_visitor to certain types 【发布时间】:2020-11-29 18:25:23 【问题描述】:

我有以下变体:

typedef boost::variant<int, float, bool> TypeVariant;

我想创建一个访问者来将intfloat 类型转换为bool 类型。


struct ConvertToBool : public boost::static_visitor<TypeVariant> 

    TypeVariant operator()(int a) const 
        return (bool)a;
    

    TypeVariant operator()(float a) const 
        return (bool)a;
    
;

但是这给了我错误信息:

'TypeVariant ConvertToBool::operator ()(float) const': 无法将参数 1 从 'T' 转换为 'float'

允许访问者仅适用于某些类型的正确方法是什么?

【问题讨论】:

为什么不简单地将 bool 转换为 bool?另外,请考虑返回 bool 而不是变体。 @Yakk-AdamNevraumont 将 bool 转换为 bool 是什么意思? 【参考方案1】:

只需包含缺少的重载:

Live On Coliru

#include <boost/variant.hpp>
#include <iostream>

using TypeVariant = boost::variant<int, float, bool>;

struct ConvertToBool 
    using result_type = TypeVariant;
    TypeVariant operator()(TypeVariant const& v) const 
        return boost::apply_visitor(*this, v);
    

    TypeVariant operator()(int   a) const  return a != 0; 
    TypeVariant operator()(float a) const  return a != 0; 
    TypeVariant operator()(bool  a) const  return a; 
 static constexpr to_bool;

int main() 
    using V = TypeVariant;
    
    for (V v : V, 42, 3.14f, true) 
        std::cout << v << " -> " << std::boolalpha << to_bool(v) << "\n";
    

概括

在更一般的情况下,您可以提供包罗万象的模板重载:

template <typename T> TypeVariant operator()(T const& a) const 
    return static_cast<bool>(a);

事实上,在你的微不足道的情况下,这就是你所需要的一切:

Live On Coliru

#include <boost/variant.hpp>
#include <iostream>

using TypeVariant = boost::variant<int, float, bool>;

struct ConvertToBool 
    using result_type = TypeVariant;
    TypeVariant operator()(TypeVariant const& v) const 
        return boost::apply_visitor(*this, v);
    

    template <typename T> TypeVariant operator()(T const& a) const 
        return static_cast<bool>(a);
    
 static constexpr to_bool;

int main() 
    using V = TypeVariant;

    for (V v :  V,  42 ,  3.14f ,  true  ) 
        std::cout << v << " -> " << std::boolalpha << to_bool(v) << "\n";
    

仍然打印

0 -> false
42 -> true
3.14 -> true
true -> true

【讨论】:

非常感谢您的详细回答。是的,这个布尔转换示例只是我的实际问题的简化问题,这些示例完美地回答了这些问题。关于您的第一个示例,我还有一个问题:当我将std::string 添加到变体中,并且未能为其指定运算符重载时,将std::string 传递给to_bool 时,它返回true。为什么会这样?我希望它会崩溃,因为没有指定重载。 我希望它不会编译,不会崩溃。但显然,是的,有一个漏洞导致它成为UB:见SEGV on Coliru。启用 asan/ubsan shows what's going on:它只是反复击中 VariantType 过载。我以前没有意识到这是该方法的潜在错误源(在可调用类型中执行apply_visitor)。 我通常是这样设置的:coliru.stacked-crooked.com/a/8efbacc6526acad6 - 单独的(私有的和潜在的静态的)call 实现prevent the infinite recursion [现在它不编译]。除了这个习惯用法之外,通过递归变体实现访问者也很优雅,因为例如return call(x) + call(y) 看起来比 return operator()(x) + operator()(y) 好,甚至更差 return (*this)(x) + (*this)(y);

以上是关于boost::variant 将 static_visitor 应用于某些类型的主要内容,如果未能解决你的问题,请参考以下文章

boost::variant 将 static_visitor 应用于某些类型

boost::variant 单一存储保证

使用 boost::variant 库制作地图。如何将事物存储和显示为正确的类型?

boost::variant 和多态性

boost::variant - 在变体上应用算术的最简单方法

利用 boost-variant 创建带有 boost::mpl::for_each 的通用工厂方法