问题
I have a class with an in-class defined friend function that I would ideally not modify (it comes from a header that's already deployed)
#include <numeric>
#include <vector>
namespace our_namespace {
template <typename T>
struct our_container {
friend our_container set_union(our_container const &, our_container const &) {
return our_container{};
}
};
} // namespace our_namespace
set_union
is not declared outside the struct or namespace, but can normally be found through argument-dependent lookup (c.f. Access friend function defined in class). However, I ran into a situation where I need the function unevaluated (i.e. without arguments to be evaluated) for template type deduction. More specifically, I would like to use the friend function as a binary operation in std::accumulate
:
auto foo(std::vector<our_namespace::our_container<float>> in) {
// what I really wanted to do:
return std::accumulate(std::next(in.begin()), in.end(), *in.begin(),
set_union);
}
The only workaround I found so far is to wrap the function call into a lambda:
auto foo(std::vector<our_namespace::our_container<float>> in) {
// what I ended up doing:
return std::accumulate(std::next(in.begin()), in.end(), in[0],
[](our_namespace::our_container<float> const& a, our_namespace::our_container<float> const& b) {return set_union(a,b);});
}
(and of cause I could define a function that does the same as the lambda).
I've tried:
- specifying the namespace for
set_union
(what I usually do to get around ADL, butset_union
isn't in a namespace) - spell out template arguments to
set_union<our_container>
(butset_union
lookup isn't failing at template argument deduction ofset_union
, and isn't templated itself) - spell out the type of
set_union
with…,decltype(set_union) set_union);
… except, here the lookup ofset_union
fails for the same reason, and providing arguments toset_union
in thedecltype
would just trigger its evaluation and lead to the return type ofset_union
rather than its type.
Is there another way to use accumulate
with ADL than this lambda?
回答1:
Using a lambda looks like the best way to me.
As @NathanOliver suggested, you could shorten it to:
[](auto const& a, auto const& b) {return set_union(a,b);}
If you insist, there is an alternative, but it's somewhat ugly.
specifying the namespace for set_union (what I usually do to get around ADL, but set_union isn't in a namespace)
It is in the namespace, but it can only be found with ADL.
If you redeclare it outside of the class, you'll be able to find it with the regular lookup:
namespace our_namespace
{
our_container<float> set_union(our_container<float> const &, our_container<float> const &);
}
auto foo(std::vector<our_namespace::our_container<float>> in)
{
// what I really wanted to do:
return std::accumulate(std::next(in.begin()), in.end(), *in.begin(),
our_namespace::set_union<float>);
}
Unfortunately, you can't declare it as a template (since it's not a template).
来源:https://stackoverflow.com/questions/54580395/how-can-i-use-adl-in-template-deduction