Good afternoon, everyone. I implemented a couple of classes:
// 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;
};
you can use it like this:
// 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;
}
In the 17 standard, you can use the following:
// 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;
}
But you can't use it like this (using 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;
}
Maybe I missed the standard information somewhere, or maybe it can't be implemented. Tell me please. I will be glad of any information.
Error:
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
If your lambda doesn't capture anything, then you can decay it to a function pointer at the call site:
and then you can add a deduction guide for
HolderDelegate
:Here's a demo.