std::begin-类型特征中未考虑用户定义的重载
std::begin - User-defined overloads not considered in type traits
考虑以下类型特征:
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);
}
在不更改include顺序的情况下,我可以做些什么来支持我的类型特征中的std::begin(foo&(?
您没有;CCD_ 5不意味着对于任意范围直接调用。如果要访问范围类型的begin/end
,则应该使用ADL和using std::begin/end
。这就是这个习语在C++中的工作原理。
在std
命名空间中重载方法是非法的,std::begin
也不例外。您可以创建std
定义的模板的模板专用化(基于用户创建的类型(,但这不是使用C++习惯用法的正确方法。
在C++20中,std::ranges::begin
函数是直接调用的,而将其专门化为类型的方法是通过ADL或成员begin
函数。所以只要使用这个成语,每个人都会好起来的。
您可以使用一点间接方法来解决此问题。
namespace adl {
namespace std_adl {
using std::begin; using std::end;
template<class T>
auto adl_begin( T&& t )
->decltype(begin(std::forward<T>(t)) )
{ return begin(std::forward<T>(t)); }
template<class T>
auto adl_end( T&& t )
->decltype(end(std::forward<T>(t)) )
{ return end(std::forward<T>(t)); }
}
template<class T>
auto begin(T&& t)
->decltype(std_adl::adl_begin(std::forward<T>(t)))
{ return std_adl::adl_begin(std::forward<T>(t)); }
template<class T>
auto end(T&& t)
->decltype(std_adl::adl_end(std::forward<T>(t)))
{ return std_adl::adl_end(std::forward<T>(t)); }
}
现在,当你想启用ADL时,无论是在你的has_begin
类型特征中还是在使用点上,都要使用adl::begin
来代替std::begin
。
对此:
namespace std {
void begin(foo&) {
}
}
这使得您的程序格式不正确,不需要进行诊断。
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- Visual C++(VS2017)中用户定义的转换不明确
- 使用用户定义的参数调用future/async并调用类方法
- 带有用户定义类的c++折叠表达式
- g++用户定义的动态链接库上的全局new和delete运算符
- 直接在 unordered_map 的方法中使用哈希,而不是生成哈希的用户定义对象
- 修改"std::set"中用户定义类型的值
- 参数包构造函数在类模板中隐藏用户定义的转换
- MAKE:找不到包含的用户定义的头文件?
- C++:用户定义的显式类型转换函数错误
- 从用户定义的类生成格式字符串?
- 为用户定义的类正确调用复制构造函数/赋值运算符
- C++ 向量与用户定义的类比较?(==, <, >)
- STL 用户定义的二进制操作
- 将用户定义的类型与 std::vector 和 std::sort 一起使用
- 为什么用户定义的函数不按照给定的顺序对相同长度的元素进行排序?
- 使用宏编译时使用用户定义的数学函数,或者仅使用 c++ 中标准数学库中的函数
- C++:用户定义的类,以成员字段作为地址