decltype(auto) 在某些情况下与 SFINAE 一起使用?
decltype(auto) works with SFINAE in some cases?
我假设 decltype(auto)
在用于尝试和 SFINAE 关闭 return 类型时是不兼容的结构。所以,当你本来会得到一个替换错误时,你会得到一个硬错误
但是为什么下面的程序可以运行呢? 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
?
的成员别名
I was under the assumption that decltype(auto)
is an incompatible construct when used to try and SFINAE off the return type.
它通常是不兼容的,因为它强制实例化函数体。如果在 body 中发生替换失败,那么这将是一个硬编译错误 - SFINAE 不适用于此处。
但是,在这个例子中,如果 T
不是默认可构造的,那么在主体中出现替换失败的唯一方法是。但是你调用 construct(T{})
,它已经要求 T
是默认可构造的——所以失败要么先发生,要么永远不会发生。
相反,发生的替换失败是在替换为 typename decltype(construct(T{}))::type
的直接上下文中发生的。当我们处于将模板参数实例化为 Foo
的直接上下文中时,试图从 int
中获取 ::type
,因此 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()
我假设 decltype(auto)
在用于尝试和 SFINAE 关闭 return 类型时是不兼容的结构。所以,当你本来会得到一个替换错误时,你会得到一个硬错误
但是为什么下面的程序可以运行呢? 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
?
I was under the assumption that
decltype(auto)
is an incompatible construct when used to try and SFINAE off the return type.
它通常是不兼容的,因为它强制实例化函数体。如果在 body 中发生替换失败,那么这将是一个硬编译错误 - SFINAE 不适用于此处。
但是,在这个例子中,如果 T
不是默认可构造的,那么在主体中出现替换失败的唯一方法是。但是你调用 construct(T{})
,它已经要求 T
是默认可构造的——所以失败要么先发生,要么永远不会发生。
相反,发生的替换失败是在替换为 typename decltype(construct(T{}))::type
的直接上下文中发生的。当我们处于将模板参数实例化为 Foo
的直接上下文中时,试图从 int
中获取 ::type
,因此 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()