考虑以下类型特征:
template<typename T, typename = void>
struct has_begin : std::false_type {};
template<typename T>
struct has_begin<T, std::void_t<
decltype(std::begin(std::declval<std::add_lvalue_reference_t<T>>()))
>> : std::true_type {};
为什么这个特性没有考虑我的用户定义重载
std::begin
?namespace std {
void begin(foo&) {}
}
int main() {
static_assert(has_begin<foo>::value); // Fails.
foo f;
std::begin(f); // Works.
}
有趣的观察结果:
- 如果我改变这个类型特征和我的重载的顺序,它就能工作
- 如果我在类型特征中使用ADL:
decltype(std::begin(std::add_lva... -> decltype(begin(std::add_lva...
如果自由函数 begin
与 foo 在相同的命名空间中,则它可以工作。
void begin(foo) {
}
但是对于除了std::之外的任何类,取决于以下因素,此方法将失败:
template<class C>
auto begin(C& c) -> decltype(c.begin());
由于 ADL 查找无法与其他名称空间中的模板配合使用,因此我需要做些什么才能在不改变包含顺序的情况下支持 std::begin(foo&)
呢?
否则,我就必须同时支持 std::begin 和 ADL begin() 这两个世界……
在我的函数中,我已经像这样做了一些事情(参考这里):
auto get_begin() {
using std::begin;
return begin(object);
}
std::begin
听起来是可以干扰的 - 但我不确定。 - Ted Lyngmo