Via*_*rus 4 c++ templates type-traits c++17
考虑以下类型特征:
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 {};
Run Code Online (Sandbox Code Playgroud)
为什么此特征不考虑我的用户定义的重载std::begin?
namespace std {
void begin(foo&) {}
}
int main() {
static_assert(has_begin<foo>::value); // Fails.
foo f;
std::begin(f); // Works.
}
Run Code Online (Sandbox Code Playgroud)
有趣的观察:
decltype(std::begin(std::add_lva... -> decltype(begin(std::add_lva...
如果free函数begin与foo位于相同的名称空间中,则它可以工作:
void begin(foo) {
}
Run Code Online (Sandbox Code Playgroud)
但是对于std ::之外的任何类都失败,具体取决于:
void begin(foo) {
}
Run Code Online (Sandbox Code Playgroud)
因为ADL查找不适用于其他名称空间的模板。
std::begin(foo&)在不更改包含顺序的情况下,我可以做些什么来支持我的类型特征?
否则,我必须同时支持这两个世界-为std :: begin和ADL begin()编写类型特征。
在我的函数中,我已经做了这样的事情(建议在这里):
auto get_begin() {
using std::begin;
return begin(object);
}
Run Code Online (Sandbox Code Playgroud)
在不更改包含顺序的情况下,我该怎么做才能在其类型特征中支持std :: begin(foo&)?
你不 std::begin并不意味着直接为任意范围调用。如果要访问begin/end范围类型,则应结合使用ADL和ADL using std::begin/end。这就是成语在C ++中的工作方式。
重载std名称空间中的方法是非法的,std::begin也不例外。您可以创建std-defined模板的模板专业化(基于用户创建的类型),但这不是使用C ++习惯用法的正确方法。
在C ++ 20中,该std::ranges::begin函数应直接调用,而针对类型专门化该函数的方法是通过ADL或成员begin函数。因此,只要使用该成语,每个人都会没事的。
| 归档时间: |
|
| 查看次数: |
95 次 |
| 最近记录: |