0

大家下午好。我实现了几个类:

// 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
4

2 回答 2

1

情况很复杂...

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

您将 a 传递std::function<std::string(std::size_t)>HolederDelegate具有等待 a 的构造函数的构造函数std::function

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

但是如果你将一个 lambda 函数传递给HolderDelegates构造函数

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

你有一种先有鸡还是先有蛋的问题,因为 lambda 可以转换为 astd::function不是a 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); }));
于 2020-08-31T15:26:35.370 回答
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...>;

这是一个演示

于 2020-08-31T15:15:44.377 回答