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 Small
s.
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++