c++ - 为什么libstdc++-v3中declval的实现看起来那么复杂?

标签 c++ c++11 templates decltype 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));
但我想我可以实现 declval简单地说:
template <typename T> T declval();
这是我的测试代码:
#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;
}
构建和运行命令是:
g++ -std=c++11 ./test.cpp
./a.out
  • 为什么libstdc++-v3中的实现看起来那么复杂?
  • 第一个片段中的模板 1 有什么作用?
  • 为什么__declval需要一个参数( int/long )?
  • 为什么模板 1 ( int ) 和模板 2 ( long ) 具有不同的参数类型?
  • 我的简单实现有什么问题吗?
  • 最佳答案

    std::declval 实际上是:

    template<class T>
    typename std::add_rvalue_reference<T>::type declval() noexcept;
    
    哪里 std::add_rvalue_reference<T> 通常是 T&& ,除非在无效的情况下(如 T = voidT = 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,编译时间提高了 4% 以上. (libc++ 实现实例化的模板较少,但它仍然有影响)
    这是通过将“add_rvalue_reference”直接内联到declval 来解决的。 .这是使用 SFINAE 完成的。
    declval<T> 的返回类型是 decltype(__declval<_Tp>(0)) .抬头时__declval ,找到两个函数模板。
    第一个有返回类型 _Up = T&& .第二个只有返回类型 T .
    第一个需要一个参数 int ,第二个 long .正在通过0 ,这是一个 int ,所以第一个函数是一个更好的匹配并被选中,并且 T&&被退回。
    除了,当 T&&不是有效类型(例如, T = void ),那么当模板参数 _Up 时替换为推导的 T&& ,存在替换失败。所以它不再是函数的候选。这意味着只剩下第二个,而 0被转换为 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

    关于c++ - 为什么libstdc++-v3中declval的实现看起来那么复杂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64060929/

    相关文章:

    c++ - 将所有权转让给经理

    c# - EntityFramework 存储库模板 - 如何在模板类中编写 GetByID lambda?

    javascript - Mustache 在 dom 中渲染实际的 HTML 标签?

    c++ - 如何使用 c/c++ 宏参数创建字符串

    C++初学者算法作业

    c++ - 使用外部模板 (C++11)

    c++ - 错误 : no member named 'rank_' in 'EndIndex'

    c++ - MFC 类和 C++ 样式转换

    c++ - IDL 文件 - 静态链接或动态链接

    c++ - 遍历另一个类中包含的 vector