我假设decltype(auto)
是不兼容的构造,用于尝试使SFINAE脱离返回类型。因此,当您原本会遇到替代错误时,会遇到硬错误
但是为什么下面的程序起作用? https://wandbox.org/permlink/xyvxYsakTD1tM3yl
#include <iostream>
#include <type_traits>
using std::cout;
using std::endl;
template <typename T>
class Identity {
public:
using type = T;
};
template <typename T>
decltype(auto) construct(T&&) {
return T{};
}
template <typename T, typename = std::void_t<>>
class Foo {
public:
static void foo() {
cout << "Nonspecialized foo called" << endl;
}
};
template <typename T>
class Foo<T,
std::void_t<typename decltype(construct(T{}))::type>> {
public:
static void foo() {
cout << "Specialized foo called" << endl;
}
};
int main() {
Foo<Identity<int>>::foo();
Foo<int>::foo();
}
用Foo
实例化int
时,我们是否会遇到硬错误?鉴于int没有名为type
的成员别名?
答案 0 :(得分:5)
我假设
decltype(auto)
是不兼容的构造,用于尝试使SFINAE脱离返回类型。
它通常是不兼容的,因为它强制实例化函数的主体。如果在 body 中发生替换失败,则将是硬编译错误-SFINAE不适用于此处。
但是,在此示例中,体内出现替换失败的唯一方法是T
不是默认可构造的。但是您用T{}
调用了construct,它已经要求它是默认可构造的-因此失败将首先发生或永远不会发生。
相反,发生的替换失败是在替换为typename decltype(construct(T{}))::type
的直接上下文中。当我们处于将模板参数实例化到::type
的直接上下文中时,试图从int
中获取Foo
的情况发生了,所以SFINAE仍然适用。
一个表明decltype(auto)
破坏SFINAE的示例是,如果我们改为将其实现为:
template <typename T>
decltype(auto) construct() {
return T{};
}
template <typename T, typename = std::void_t<>>
class Foo {
public:
static void foo() {
cout << "Nonspecialized foo called" << endl;
}
};
template <typename T>
class Foo<T,
std::void_t<typename decltype(construct<T>())::type>> {
public:
static void foo() {
cout << "Specialized foo called" << endl;
}
};
然后尝试实例化:
struct X {
X(int);
};
Foo<X>::foo(); // hard error, failure is in the body of construct()