在std :: visit中跳过变体类型的某些重载组合有哪些方法?

时间:2018-08-29 10:15:25

标签: c++ c++17

std::visit支持多种输入形式。但是,该代码应处理这些变体中所有类型的组合。

有没有办法跳过不“有意义的”组合?

例如:

template<class... Ts> 
struct overloaded : Ts... { using Ts::operator()...; };

template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

int main() {
    std::variant<int, float, char> v1 { 's' };
    std::variant<int, float, char> v2 { 10 };

    std::visit(overloaded{
        [](int a, int b) { },
        [](int a, float b) { },
        [](int a, char b) { },
        [](float a, int b) { },
        [](float a, float b) { },
        [](float a, char b) { },
        [](char a, int b) { },
        [](char a, float b) { },
        [](char a, char b) { }
    }, v1, v2);

    return 0;
}

是否有机会仅实现几个重要的组合,而将其余的“保留”? (当然,现在,如果您忘记实现一个组合,编译器将报告令人讨厌的错误...)

也许是通用lambda?

std::visit(overloaded{
        [](int a, int b) { },
        [](int a, float b) { },
        [](int a, char b) { },
        [](float a, int b) { },
        [](auto a, auto b) { }, // <<
    }, v1, v2);

那行得通,但是我想知道是否有更好的解决方案?

更新: 这是答案中提到的解决方案的游乐场: http://coliru.stacked-crooked.com/a/78d9f2f25789bad2

2 个答案:

答案 0 :(得分:7)

是的,通用lambda是一个很好的解决方案。您建议的解决方案实际上可以发挥作用。

通常使用过载规则。

[](auto a, auto b)
在这个意义上

template <class T1, class T2> auto foo(T1 a, T2 b) const;

任何与非模板重载之一不完全匹配的东西都将称为通用lambda。

您可以通过提供诸如[] (int a, auto b)[] (auto a, auto b)之类的东西来混淆一些内容。仍然适用通常的重载规则。

或者与[]<class T>(T a, T b)(自C ++ 20起)混合使用

答案 1 :(得分:3)

另一种选择是将overloaded更改为以下内容:

template<class... Ts>
struct overloaded_or_no_op : Ts...
{
    using Ts::operator()...;

    template<class... Us>
    void operator()(const Us&...) const {  }
};

template<class... Ts> overloaded_or_no_op(Ts...) -> overloaded_or_no_op<Ts...>;