我一直试图通过阅读下面的文章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右边的表达式(λ)实际上是什么?评估中的执行顺序是什么?在hasSeriaize中,auto的值是什么?
请帮助我理解这一点,因为我已经挣扎了一周,但仍然无法理解它。如果有人能给出一个实际的例子,我将不胜感激。
谢谢
发布于 2017-03-10 17:37:15
首先,这段代码使用了boost::hana::is_valid --确保阅读它的文档并理解它在做什么。
是hasSerialize是一种方法吗?
不是,它是一个用lambda表达式初始化的变量。它是一个closure。
hasSerialize右边的表达式(
)实际上是什么?
以下代码..。
auto hasSerialize = is_valid([](auto&& x) -> decltype(x.serialize()) { });...will创建一个函数对象,当使用对象调用时,如果y.serialize()是有效表达式,则y将返回std::true_type,否则返回std::false_type。示例:
struct Foo { };
struct Bar { void serialize() { } };
static_assert(!hasSerialize(std::declval<Foo>()));
static_assert(hasSerialize(std::declval<Bar>()));下面是is_valid的一个简单的可能实现
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>{};
}它简单地使用std::is_callable来查看是否可以使用一些特定的参数来调用带有尾随decltype的通用lambda。如果尾随的decltype 中的表达式对于某些特定的参数类型无效,则是不可调用的。
可以使用void_t以SFINAE友好的方式实现is_callable,如下所示
template <typename...>
using void_t = void;
template <typename, typename = void>
struct is_callable : std::false_type { };
template <typename TF, class... Ts>
struct is_callable<TF(Ts...),
void_t<decltype(std::declval<TF>()(std::declval<Ts>()...))>>
: std::true_type { };https://stackoverflow.com/questions/42714716
复制相似问题