How can I use ADL in template deduction?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-11 06:06:10

问题


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, but set_union isn't in a namespace)
  • spell out template arguments to set_union<our_container> (but set_union lookup isn't failing at template argument deduction of set_union, and isn't templated itself)
  • spell out the type of set_union with …,decltype(set_union) set_union); … except, here the lookup of set_union fails for the same reason, and providing arguments to set_union in the decltype would just trigger its evaluation and lead to the return type of set_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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!