如何在模板推导中使用ADL?

时间:2019-02-07 18:57:40

标签: c++ argument-dependent-lookup friend-function

我有一个带有类内定义的好友函数的类,我理想上不会修改它(它来自已部署的标头)

#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不在结构或名称空间之外声明,但通常可以通过依赖于参数的查找(参见Access friend function defined in class)进行查找。但是,我遇到了一种情况,我需要对模板类型推导使用未经评估的函数(即无需评估参数)。更具体地说,我想在std::accumulate中将friend函数用作二进制操作:

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);
}

到目前为止,我发现的唯一解决方法是将函数调用包装到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);});
}

(因此,我可以定义一个与lambda相同的函数)。

我尝试过:

  • 指定set_union的名称空间(我通常会做些什么来解决ADL,但是set_union不在名称空间中)
  • 将模板参数拼写为set_union<our_container>(但是set_union的查找不会推论set_union的模板参数,并且本身也没有模板化)
  • set_union拼写…,decltype(set_union) set_union);的类型……,除了set_union的查找由于相同的原因而失败,并在{{ 1}}只会触发其评估并返回set_union的返回类型,而不是其类型。

除了此lambda之外,还有其他方法可以将decltype用于ADL吗?

1 个答案:

答案 0 :(得分:3)

使用lambda似乎是我的最佳方法。

按照@NathanOliver的建议,您可以将其缩短为:

[](auto const& a, auto const& b) {return set_union(a,b);}

如果您坚持认为,还有另一种选择,但这有点难看。

  

指定set_union的名称空间(我通常会这样做以避开ADL,但set_union不在名称空间中)

它是 在命名空间中,但是只能通过ADL找到。

如果您在课程之外重新声明它,则可以通过常规查找来找到它:

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>);
}

不幸的是,您不能将其声明为模板(因为它不是模板)。