【问题标题】:boost::static_visitor failed to specialise function template with multiple different possible typesboost::static_visitor 未能专门化具有多种不同可能类型的函数模板
【发布时间】:2020-08-13 12:34:18
【问题描述】:

我正在尝试创建一个访问者函数,它将我的boost::variant 的值相加。我在类型不同的情况下使用模板,例如int + float

typedef boost::variant<int, float> Values;

struct Add : public boost::static_visitor<Values> {
    template <typename T, typename U>
    auto operator() (T a, U b) const -> decltype(a + b) {
        return a + b;
    }
}

这编译和工作正常

std::cout << boost::apply_visitor(Add{}, (Values)2, (Values)5) << std::endl;
std::cout << boost::apply_visitor(Add{}, (Values)2, (Values)5.123) << std::endl;

7

7.123

不过,我还想将std::string 添加到Values 变体中,这样我也可以将字符串加在一起。我知道例如 string + int 是不可能的,但我会确保 Values 在尝试通过访问者运行它们之前都是一个字符串。

typedef boost::variant<int, float, std::string> Values;
std::cout << boost::apply_visitor(Add{}, (Values)"hello", (Values)"world") << std::endl;

但是程序没有编译,给我错误:

无法专门化函数模板'unknown-type Add::operator ()(T,U) const'

我知道std::string 是一个对象而不是一个类型,因此这种错误是有道理的,所以我试图通过在Add 结构中重载operator 来创建一个特殊情况都是字符串:

auto operator() (std::string a, std::string b) const {
    return a + b;
}

但是我得到了错误

std::basic_string,std::allocator> Add::operator ()(std::string,std::string) const': 无法将参数 1 从 'T' 转换为 'std::string'

看起来它仍在尝试通过模板化访问者运行字符串参数。我哪里错了?有没有更好的方法来实现我想要做的事情?抱歉,如果答案很明显,我对 C++、boost 和模板还是很陌生。

【问题讨论】:

    标签: c++ templates boost operator-overloading sfinae


    【解决方案1】:

    apply_visitor 应该处理所有组合(即使你是无效的)。

    你可以这样做:

    using Values = boost::variant<int, float, std::string>;
    
    // Helper for overload priority
    struct low_priority {};
    struct high_priority : low_priority{};
    
    struct Add : public boost::static_visitor<Values> {
    
        template <typename T, typename U>
        auto operator() (high_priority, T a, U b) const -> decltype(Values(a + b)) {
            return a + b;
        }
    
        template <typename T, typename U>
        Values operator() (low_priority, T, U) const {
            // string + int, float + string, ...
            throw std::runtime_error("Incompatible arguments");
        }
    
        template <typename T, typename U>
        Values operator() (T a, U b) const {
            return (*this)(high_priority{}, a, b);
        }
    };
    

    【讨论】:

    • 感谢您的回答。只是尝试跟随您的代码,它如何确定输入是低优先级还是高优先级?
    • @Tom: high_priority 超载使用 SFINAE。因此,当两个重载都可行时,high_priority 具有完全匹配,而 low_priotity 已派生为基本转换,因此 high_priority 获胜。如果 SFINAE 丢弃了高优先级,则仅保留 low_priority
    • 非常感谢。今天学到了新东西!
    • 优先级可能被某些整数类型和 C 省略号替换(当在参数列表的末尾时),但它不能很好地扩展,并且意图不太清楚(即使通常用于使用 SFINAE 创建特征)。
    猜你喜欢
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多