我一直在尝试通过阅读以下文章Link来了解SFINAE技巧,但却难以理解它的某些部分。
完整代码:Link
我对这些代码行感到困惑。
// Check if a type has a serialize method.
auto hasSerialize = is_valid([](auto&& x)
-> decltype(x.serialize()) { });
template <class T> auto serialize(T& obj)
-> typename std::enable_if<decltype(hasSerialize(obj))::value, std::string>::type
{
return obj.serialize();
}
template <class T> auto serialize(T& obj)
-> typename std::enable_if<!decltype(hasSerialize(obj))::value, std::string>::type
{
return to_string(obj);
}
特别是对于hasSerialize行,它在带有参数的decltype中使用。谁能告诉我这里有什么东西? hasSerialize是一种方法吗? hasSerialize右侧的表达式(lambda)将实际评估为什么?评估中的执行顺序是什么?在hasSeriaize中自动计算的内容是什么?
请帮助我理解这一点,因为我在这个问题上挣扎了一个星期,但仍然可以解决这个问题。如果任何人能够提供一个实际的例子,我将不胜感激。
由于
答案 0 :(得分:1)
首先,此代码使用boost::hana::is_valid
- 请务必阅读其文档并了解它的作用。
hasSerialize是一种方法吗?
不,它是用lambda表达式初始化的变量。这是closure。
hasSerialize右侧的表达式(lambda)将实际评估为什么?
以下代码......
auto hasSerialize = is_valid([](auto&& x) -> decltype(x.serialize()) { });
...将创建一个函数对象,当使用对象y
调用时,如果std::true_type
是有效表达式{{1},则返回y.serialize()
}} 除此以外。例如:
std::false_type
这是struct Foo { };
struct Bar { void serialize() { } };
static_assert(!hasSerialize(std::declval<Foo>()));
static_assert(hasSerialize(std::declval<Bar>()));
的简单可能实现:
is_valid
它只是使用std::is_callable
来查看是否可以使用某些特定参数调用带有尾随template <typename TF>
struct validity_checker
{
template <typename... Ts>
constexpr auto operator()(Ts... ts)
{
return std::is_callable<
TF(typename decltype(ts)::type...)
>{};
}
};
template <typename TF>
constexpr auto is_valid(TF)
{
return validity_checker<TF>{};
}
的泛型lambda 。 如果尾部decltype
内的表达式对某些特定参数类型无效,则lambda不可调用。
decltype
可以使用is_callable
以符合SFINAE的方式实施,如下所示:
void_t