【问题标题】:Need clarification about Lambdas, auto and decltype in SFINAE需要澄清 SFINAE 中的 Lambdas、auto 和 decltype
【发布时间】:2017-03-10 09:25:23
【问题描述】:

我一直在尝试通过阅读以下文章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 中 auto 的结果是什么?

请帮助我理解这一点,因为我为此苦苦挣扎了一周,但仍然无法理解。如果有人能给出一个实际的例子,将不胜感激。

谢谢

【问题讨论】:

    标签: c++ templates lambda sfinae auto


    【解决方案1】:

    首先,此代码使用boost::hana::is_valid - 请务必阅读其文档并了解它在做什么。


    hasSerialize 是一个方法吗?

    不,它是一个用 lambda 表达式初始化的变量。这是一个closure


    hasSerialize 右侧的表达式(lambda)实际上会计算为什么?

    以下代码...

    auto hasSerialize = is_valid([](auto&& x) -> decltype(x.serialize()) { });
    

    ...将创建一个 函数对象,当使用对象 y 调用该对象时,如果 y.serialize() 是有效表达式,则返回 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 中的表达式对于某些特定参数类型无效,则 lambda 不可调用。


    is_callable 可以通过以下对 SFINAE 友好的方式实现,使用 void_t

    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 { };
    

    【讨论】:

    • 感谢您的回答。我会仔细阅读您的答案,看看是否可以通过阅读有关 lamdas 的更多信息来解决这个问题(关闭,因为我仍然没有从您的链接中得到它)。将在一天内回复您。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 2012-07-18
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多