Search code examples
c++c++17variantstdbind

Using std::bind with std::visit


I'm trying to use std::bind together with std::visit in order to get a function where the visitor is bound.

I'm getting a "no instance of overloaded function" but I have no idea what I'm doing wrong with regards to bind.

How do I utilize std::bind to capture the visitor?

#include <variant>
#include <functional>
#include <iostream>

using Somenum = std::variant<uint64_t, double>;

struct Visitor {
    uint64_t operator()(const uint64_t& num) const {
        return num;
    }
    uint64_t operator()(const double& num) const{
        return 5;
    }
};

int main(int argc, char **argv) {
    const Somenum a = 3.0;
    const Somenum b = (uint64_t)6;
    const Visitor v{};
    const auto f = std::bind(std::visit<Visitor, Somenum>, v, std::placeholders::_1);
    const auto f2 = [&v](Somenum x) {
        return std::visit(v, x);
    };

    std::cout << f(a) << std::endl << f(b)<< std::endl;

    std::cout << f2(a) << std::endl << f2(b) << std::endl;
    return 0;
}

Effectively I'd like f and f2 to have the same behavior

Removing the line where f is called allows everything to compile.


Solution

  • I can't explain the <unresolved overloaded function type> error - but what you're doing is incorrect anyway. std::visit takes a bunch of forwarding references, so std::visit<Visitor, Somenum> is a function pointer whose type is something like:

    decltype(auto)(*)(Visitor&&, Somenum&&);
    

    Those are rvalue references. But you're not actually invoking this function with rvalues, you're invoking it with lvalues. const lvalues even. So the version you want is really std::visit<Visitor const&, Somenum const&>. This works:

    auto p = std::visit<Visitor const&, Somenum const&>;
    const auto f = std::bind(p, v, std::placeholders::_1);
    

    Again I'm not sure why you need to pre-declare p.


    This should hopefully make it clear why using the lambda is strongly preferred. You don't have to manually before template argument deduction just to get it right!