exp*_*ter 49 c++ templates decltype c++11 declval
下面的代码来自 libstdc++-v3 std::type_traits,它是一个实现std::declval:
template<typename _Tp, typename _Up = _Tp&&> // template 1
_Up
__declval(int);
template<typename _Tp> // template 2
_Tp
__declval(long);
template<typename _Tp> // template 3
auto declval() noexcept -> decltype(__declval<_Tp>(0));
Run Code Online (Sandbox Code Playgroud)
但我认为我可以declval简单地实现:
template <typename T> T declval();
Run Code Online (Sandbox Code Playgroud)
这是我的测试代码:
#include <iostream>
using namespace std;
struct C {
C() = delete;
int foo() { return 0; }
};
namespace test {
template <typename T> T declval();
};// namespace test
int main() {
decltype(test::declval<C>().foo()) n = 1;
cout << n << endl;
}
Run Code Online (Sandbox Code Playgroud)
构建和运行命令是:
g++ -std=c++11 ./test.cpp
./a.out
Run Code Online (Sandbox Code Playgroud)
__declval需要参数(int/ long)?int) 和模板 2 ( long) 具有不同的参数类型?Art*_*yer 57
std::declval 实际上是:
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
Run Code Online (Sandbox Code Playgroud)
std::add_rvalue_reference<T>通常在哪里T&&,除非在无效的情况下(如 ifT = void或T = int() const),它只是T。主要区别在于函数不能返回数组,但可以返回数组引用,如U(&&)[]或U(&&)[N]。
显式使用的问题std::add_rvalue_reference在于它实例化了一个模板。在 libstdc++ 实现中,它本身以 ~4 的实例化深度实例化了大约 10 个模板。在通用代码中,std::declval可以使用很多,并且根据https://llvm.org/bugs/show_bug.cgi?id=27798,不使用std::add_rvalue_reference. (libc++ 实现实例化的模板较少,但它仍然有影响)
这是通过将 " add_rvalue_reference" 直接内联到declval. 这是使用 SFINAE 完成的。
的返回类型declval<T>是decltype(__declval<_Tp>(0))。查找时__declval,发现两个函数模板。
第一个有返回类型_Up = T&&。第二个只有返回类型T。
第一个需要一个参数int,第二个long。它正在被传递0,它是一个int,所以第一个函数是一个更好的匹配并被选择,并被T&&返回。
除了 whenT&&不是有效类型(例如,T = void),然后当模板参数_Up被推导T&&的 替换时,会出现替换失败。所以它不再是函数的候选。这意味着只剩下第二个,并且 the0被转换为 long (并且返回类型只是T)。
在不能从函数返回T和 的情况下T&&(例如,T = int() const),两个函数都不能被选中,并且该std::declval<T>函数具有替换失败并且不是可行的候选者。
这是介绍优化的 libc++ 提交:https : //github.com/llvm/llvm-project/commit/ae7619a8a358667ea6ade5050512d0a27c03f432
这是 libstdc++ 提交:https ://gcc.gnu.org/git/?p = gcc.git;a = commitdiff;h = ec26ff5a012428ed864b679c7c171e2e7d917f76
他们俩以前都是 std::add_rvalue_reference<T>::type
Pas*_* By 18
这是为了捕获无法形成引用的类型。特别是,void。
通常int选择过载。如果_Tp是void,则int重载将失败_Up = void&&,然后long选择重载。
您的实现不会添加引用,这会因数组和函数而失败。
test::declval<void()>() // fails
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2259 次 |
| 最近记录: |