Fix or alternative to ADL when one of the functions is actually a function object

In the following code, the standalone component in the namespace S has its own definitions of Big and Small types, together with a split function to split one Big into a collection of the Smalls.

S also provides another function, work, which makes use of split, and is meant to be used by S itself and also by other dependent components, e.g. the one in the namespace D, which are assumed to provide their own definitions of Big and Small and their own definition of split, which will be identified via ADL.¹

#include <iostream>
#include <string>
#include <utility>
#include <vector>

namespace S /* standalone */ {
    struct Big{};
    struct Small{};
    std::vector<Small> split(Big b) {
        std::cout << "S" << std::endl;
        return {/* use b to make output */};
    }
    template<typename BigT>
    void work(BigT/* acutally this is a template class with `BigT` as a template paramter*/ x) {
        split(x); // correspondingly `split` is not applied on `x` but on the `BigT` which is part of it
        // a lot of complex stuff
    }
}

namespace D /* dependent on standalone */ {
    struct Big{};
    struct Small{};
    std::vector<Small> split(Big b) {
        std::cout << "D" << std::endl;
        return {/* use b to make output */};
    }
}
int main() {
    S::Big line1{};
    D::Big line2{};
    S::work(line1); // uses S::split
    S::work(line2); // uses D::split
}

Well, in reality S::split is a function object, not a function²,

namespace S {
    struct Split {
        std::vector<Small> operator()(Big) const {
            std::cout << "S" << std::endl;
            return {};
        }
    } split;
}

so ADL doesn’t work.

Any suggestion on how to address these needs?


¹ Originally work was defined in both S and D, and the code above is my attempted refactoring, during which I run into the described issue.

² The reason for this is that S::split is used in several contexts in S, it has a few overloads of operator(), and most importantly, it’s often passed around as an object, which is very handy.

Source: Windows Questions C++

LEAVE A COMMENT