如何在模板推导中使用 ADL?
How can I use ADL in template deduction?
我有一个 class 和一个 in-class 定义的友元函数,我最好不要修改它(它来自一个已经部署的 header)
#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
未在结构或命名空间外声明,但通常可以通过 argument-dependent 查找(c.f. Access friend function defined in class)找到。但是,我 运行 遇到了这样一种情况,我需要对函数进行未求值(即没有要求值的参数)以进行模板类型推导。更具体地说,我想将 friend 函数用作 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);
}
到目前为止我发现的唯一解决方法是将函数调用包装到 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
的模板参数推导中没有失败,并且本身没有模板化)
- 用
…,decltype(set_union) set_union);
拼出 set_union
的类型……除了,这里 set_union
的查找由于同样的原因失败,并在 set_union
中提供参数decltype
只会触发它的评估并导致 return 类型 set_union
而不是它的类型。
除了这个 lambda,还有其他方法可以将 accumulate
与 ADL 一起使用吗?
我认为使用 lambda 是最好的方法。
正如@NathanOliver 所建议的,您可以将其缩短为:
[](auto const& a, auto const& b) {return set_union(a,b);}
如果你坚持,还有一个选择,但有点难看。
specifying the namespace for set_union (what I usually do to get around ADL, but set_union isn't in a namespace)
它是在命名空间中,但只能用ADL找到。
如果您在 class 之外重新声明它,您将能够通过常规查找找到它:
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>);
}
遗憾的是,您不能将其声明为模板(因为它不是模板)。
我有一个 class 和一个 in-class 定义的友元函数,我最好不要修改它(它来自一个已经部署的 header)
#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
未在结构或命名空间外声明,但通常可以通过 argument-dependent 查找(c.f. Access friend function defined in class)找到。但是,我 运行 遇到了这样一种情况,我需要对函数进行未求值(即没有要求值的参数)以进行模板类型推导。更具体地说,我想将 friend 函数用作 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);
}
到目前为止我发现的唯一解决方法是将函数调用包装到 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
的模板参数推导中没有失败,并且本身没有模板化) - 用
…,decltype(set_union) set_union);
拼出set_union
的类型……除了,这里set_union
的查找由于同样的原因失败,并在set_union
中提供参数decltype
只会触发它的评估并导致 return 类型set_union
而不是它的类型。
除了这个 lambda,还有其他方法可以将 accumulate
与 ADL 一起使用吗?
我认为使用 lambda 是最好的方法。
正如@NathanOliver 所建议的,您可以将其缩短为:
[](auto const& a, auto const& b) {return set_union(a,b);}
如果你坚持,还有一个选择,但有点难看。
specifying the namespace for set_union (what I usually do to get around ADL, but set_union isn't in a namespace)
它是在命名空间中,但只能用ADL找到。
如果您在 class 之外重新声明它,您将能够通过常规查找找到它:
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>);
}
遗憾的是,您不能将其声明为模板(因为它不是模板)。