【发布时间】:2018-01-16 23:39:09
【问题描述】:
关于以下代码(为方便起见,以下转载https://wandbox.org/permlink/nhx4pheijpTF1ohf)
#include <type_traits>
#include <utility>
namespace foo_name {
template <typename T>
void foo();
template <>
void foo<int>();
template <typename T>
struct c_size;
template <>
struct c_size<int> : public std::integral_constant<int, 1> {};
} // namespace foo_name
template <typename Type>
class Foo {
public:
template <typename T>
static decltype(auto) impl(T&& t) {
using foo_name::foo;
return foo(std::forward<T>(t));
}
};
class Something {};
template <typename Type, typename T = std::decay_t<Type>>
using EnableIfHasFoo = std::void_t<
decltype(Foo<T>::impl(std::declval<T>())),
decltype(foo_name::c_size<Type>::value)>;
template <typename Type, typename = std::void_t<>>
class Test {};
template <typename Type>
class Test<Type, EnableIfHasFoo<Type>> {};
int main() {
static_cast<void>(Test<Something>{});
}
上面的代码以错误退出,因为Foo<T>::impl() 的实例化导致了一个硬错误并且在 SFINAE 上下文中不可用。但是这里奇怪的是,当你在EnableIfHasFoo中切换void_t中的东西的顺序(到下面的https://wandbox.org/permlink/at1KkeCraNwHGmUI),它会编译
template <typename Type, typename T = std::decay_t<Type>>
using EnableIfHasFoo = std::void_t<
decltype(foo_name::c_size<Type>::value),
decltype(Foo<T>::impl(std::declval<T>()))>;
现在问题是
- 为什么代码最初无法编译?
Foo<T>::impl()的实例化是在替换的上下文中,所以它应该可以工作吗? - 用
foo_name::foo(T)代替void_t的第一个参数将使它编译(参见https://wandbox.org/permlink/g3NaPFZxdUPBS7oj),为什么?添加一个额外的间接层如何使情况有所不同? - 为什么
void_t中的顺序会有所不同,编译器是否会短路类型包中的表达式?
【问题讨论】:
标签: c++ templates c++17 sfinae