decltype 在模板参数推导失败的地方成功?

decltype succeeds where template argument deduction fails?

我想知道为什么当带有 bbb 的行没有被注释掉但它前面的行被注释掉时,为什么下面的代码可以按预期编译和工作,但是当带有 aaa 标记的行没有被注释掉时它确实失败了注释掉 bbb 行是:

#include <iostream>
#include <string>
using String = std::string;
struct Person {
    String m_name;
    explicit Person(String const &name): m_name(name) {}
    operator String() const { return "\"" + m_name + "\""; }
};

template<class T> bool isEqual(
T const& a,
//T const& // does NOT compile // aaa
decltype(a) // DOES compile    // bbb
b){ return a == b; }

int main()
{
    String const  plain("plain");
    Person const jb("James");
    bool b = isEqual(plain, jb);
    std::cout << "isEqual(plain, person) is " << ( b ? "true" : "false" ) << "\n";
}

当你这样做时:

template<class T> 
bool isEqual(T const& a, T const& b)

T 推断为不同的类型(String 代表 aPerson 代表 b)。由于 T 只能是一种类型,所以推导失败。

但是,当您这样做时:

template<class T> 
bool isEqual(T const& a, decltype(a) b)

只需要推导一对parameter/argument。 T 被推导为 String,并且由于 Person 可以转换为 String(通过转换函数 operator String()),这很好用。

这类似于 identity 技巧,我们只是强制一个参数处于非推导上下文中:

template <typename T>
struct identity { using type = T; };

template <typename T>
bool isEqual(T const& a, typename identity<T>::type const& b);

在这里,只有一对发生类型推导,T 被推导为 String - 因此 b 的类型也是 String const& ,但不是因为它是这样推导出来的——因为它被替换了。