如何将CTAD用于lambda?

问题描述

大家下午好。我实现了两节课:

// CallingDelegate
template <typename Result,typename ... Args>
class CallingDelegate
{
    using TypeDelegate = std::function<Result(Args...)>;
public:
    CallingDelegate() = delete;
    CallingDelegate(const std::shared_ptr<TypeDelegate>& boxDelegate) : m_boxDelegate(boxDelegate) {}
public:
    Result operator()(Args... args) const
    {
        if (m_boxDelegate)
        {
            const auto& delegate = (*m_boxDelegate.get());
            if (delegate)
            {
                return delegate(std::forward<Args>(args)...);
            }
        }
        return {};
    }
private:
    const std::shared_ptr<TypeDelegate> m_boxDelegate;
};
// HolderDelegate
template <typename Result,typename ... Args>
class HolderDelegate
{
    using TypeDelegate = std::function<Result(Args...)>;
public:
    using TypeCalling  = CallingDelegate<Result,Args...>;
public:
    ~HolderDelegate() { (*m_boxDelegate.get()) = nullptr; }
    HolderDelegate() = delete;
    HolderDelegate(const TypeDelegate& delegate) : m_boxDelegate(std::make_shared<TypeDelegate>    (delegate)) {}
    //
    template<typename TypeCallback>
    HolderDelegate(const TypeCallback& callback) : m_boxDelegate(std::make_shared<TypeDelegate>    (TypeDelegate(callback))) {}
public: /// NON COPY
    HolderDelegate(const HolderDelegate&) = delete;
    HolderDelegate& operator=(const HolderDelegate& other) = delete;
public:
    inline TypeCalling getCalling() const { return TypeCalling(m_boxDelegate); }
private:
    const std::shared_ptr<TypeDelegate> m_boxDelegate;
};

您可以像这样使用它:

// Func
void runDelegate(const std::function<std::string(size_t)> delegate)
{
    for (size_t i = 0; i < 3; ++i)
    {
        printf("index: %zu => text: %s\n",i,delegate(i).c_str());
    }
}
// Main
int main()
{
    std::function<std::string(size_t)> delegate;
    {
        const HolderDelegate<std::string,size_t> holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
        delegate = holder.getCalling();
        runDelegate(delegate);
    }
    runDelegate(delegate);
    return 0;
}

在17标准中,您可以使用以下内容:

// Main
int main()
{
    std::function<std::string(size_t)> delegate;
    {
        const std::function<std::string(size_t)> delegateRaw = [] (const size_t index) -> std::string {     return std::to_string(index); };
        const HolderDelegate holder (delegateRaw);
        delegate = holder.getCalling();
        runDelegate(delegate);
    }
    runDelegate(delegate);
    return 0;
}

但是您不能这样使用它(使用lambda):

// Main
int main()
{
    std::function<std::string(size_t)> delegate;
    {
        const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
        delegate = holder.getCalling();
        runDelegate(delegate);
    }
    runDelegate(delegate);
    return 0;
}

也许我错过了某个地方的标准信息,或者也许无法实现。请告诉我。我将很高兴收到任何信息。

错误:

main.cpp: In function 'int main()':
main.cpp:65:104: error: class template argument deduction     failed:
   const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
                                                                                                            ^
main.cpp:65:104: error: no matching function for call to     'HolderDelegate(main()::<lambda(size_t)>)'
main.cpp:44:2: note: candidate: 'template<class Result,class     ... Args> HolderDelegate(const HolderDelegate<Result,Args>&)->     HolderDelegate<Result,Args>'
  HolderDelegate(const HolderDelegate&) = delete;
  ^~~~~~~~~~~~~~
main.cpp:44:2: note:   template argument deduction/substitution     failed:
main.cpp:65:104: note:   'main()::<lambda(size_t)>' is not     derived from 'const HolderDelegate<Result,Args>'
   const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
                                                                                                            ^
main.cpp:42:2: note: candidate: 'template<class Result,class     ... Args,class TypeCallback> HolderDelegate(const TypeCallback&)->     HolderDelegate<Result,Args>'
  HolderDelegate(const TypeCallback& callback) :     m_boxDelegate(std::make_shared<TypeDelegate>(TypeDelegate(callback))) {}
  ^~~~~~~~~~~~~~
main.cpp:42:2: note:   template argument deduction/substitution     failed:
main.cpp:65:104: note:   couldn't deduce template parameter     'Result'
   const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
                                                                                                            ^
main.cpp:39:2: note: candidate: 'template<class Result,class     ... Args> HolderDelegate(const TypeDelegate&)-> HolderDelegate<Result,Args>'
  HolderDelegate(const TypeDelegate& delegate) :     m_boxDelegate(std::make_shared<TypeDelegate>(delegate)) {}
  ^~~~~~~~~~~~~~
main.cpp:39:2: note:   template argument deduction/substitution     failed:
main.cpp:65:104: note:   'main()::<lambda(size_t)>' is not     derived from 'const TypeDelegate'
   const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
                                                                                                            ^
main.cpp:38:2: note: candidate: 'template<class Result,class     ... Args> HolderDelegate()-> HolderDelegate<Result,Args>'
  HolderDelegate() = delete;
  ^~~~~~~~~~~~~~
main.cpp:38:2: note:   template argument deduction/substitution     failed:
main.cpp:65:104: note:   candidate expects 0 arguments,1     provided
   const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
                                                                                                            ^
main.cpp:31:7: note: candidate: 'template<class Result,class     ... Args> HolderDelegate(HolderDelegate<Result,Args>)-> HolderDelegate<Result,Args>'
 class HolderDelegate
       ^~~~~~~~~~~~~~
main.cpp:31:7: note:   template argument deduction/substitution     failed:
main.cpp:65:104: note:   'main()::<lambda(size_t)>' is not     derived from 'HolderDelegate<Result,Args>'
   const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });
                                                                                                            ^
mingw32-make[1]: *** [Makefile.Debug:105: debug/main.o] Error 1

解决方法

如果您的lambda没有捕获任何东西,那么您可以将其衰减到调用站点的函数指针:

const HolderDelegate holder ( + [] (const size_t index) -> std::string { return std::to_string(index); });
                           // ^ decay to FP

然后您可以为HolderDelegate添加一个推导指南:

template <typename Result,typename ... Args>
HolderDelegate(Result (*)(Args...)) -> HolderDelegate<Result,Args...>;

这里是demo

,

这很复杂...

使用

    const std::function<std::string(size_t)> delegateRaw = [] (const size_t index) -> std::string {     return std::to_string(index); };
    const HolderDelegate holder (delegateRaw);

您将std::function<std::string(std::size_t)>传递给HolederDelegate构造函数,该构造函数要等待std::function

因此,新的(C ++ 17)自动演绎指南将HolderDelegates检测为HolderDelegates<std::string,std::size_t>

但是如果您将lambda函数传递给HolderDelegates构造函数

    const HolderDelegate holder ([] (const size_t index) -> std::string {     return std::to_string(index); });

您遇到了种鸡与蛋的问题,因为lambda可以转换为std::function,但不是 std::function

因此无法推论std::function的类型,并且自动推论指南不起作用。

要解决此问题,我看到树可能的解决方案。

第一个是您的工作方式

    const std::function<std::string(size_t)> delegateRaw = [] (const size_t index) -> std::string {     return std::to_string(index); };
    const HolderDelegate holder (delegateRaw);

第二个是明确的HolderDelegates类型,因此根本不需要推论。

    // .................VVVVVVVVVVVVVVVVVVVVVVVvvv
    const HolderDelegate<std::string,std::size_t> holder ([] (const size_t index) -> std::string {     return std::to_string(index); });

第三个是std::function的推导指南,

    // ..........................VVVVVVVVVVVVVV...........................................................................-V
    const HolderDelegate holder (std::function([] (const size_t index) -> std::string {     return std::to_string(index); }));

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...