2

Let's say we have this simplified version of my code:

template<typename R>
R Context::executeTransient(std::function<R(VkCommandBuffer)> const &commands) {
    ...
    R result = commands(commandBuffer);
    ...
    return result;
}

I tried to pass a lambda function as a parameter to the function Context::executeTransient() but it works only if I explicitly assign the lambda to a specific std::function type. This works:

std::function<int(VkCommandBuffer)> f = [](VkCommandBuffer commandBuffer) {
    printf("Test execution");
    return 1;
};
context.executeTransient(f);

The example above works but I'd like to achieve the example below because of aesthetic reasons and don't know if this is even possible:

context.executeTransient([](VkCommandBuffer commandBuffer) {
    printf("Test execution");
    return 1;
});

My only requirement is that Context::executeTransient() should accept lambdas and functions with a templated return type and input argument with some specific type e.g. VkCommandBuffer.

max66
  • 65,235
  • 10
  • 71
  • 111
batthomas
  • 417
  • 5
  • 12

1 Answers1

3

What about simply as follows ?

template <typename F>
auto Context::executeTransient (F const & commands) {
    ...
    auto result = commands(commandBuffer);
    ...
    return result;
}

This way your method accept both standard functions and lambdas (without converting them to standard functions, that is preferable, from the performance point of view (as far as I know)) and the return type is deduced from the use (auto).

In you need to know the R type inside the method, you can apply decltype() to result

     auto result = commands(commandBuffer);

     using R = decltype(result);

If you need to know the R type as template parameter of the method, its a little more complex because involve std::declval() and, unfortunately, add redundancy

template <typename F,
          typename R = decltype(std::declval<F const &>()(commandBuffer))>
R Context::executeTransient (F const & commands) {
    ...
    R result = commands(commandBuffer);
    ...
    return result;
}
max66
  • 65,235
  • 10
  • 71
  • 111
  • The first code snippet works perfectly if I put the implementation in the header. The third one would also work if `commandBuffer` wasn't a local variable. Is there any workaround besides copying the implementation in the header? – batthomas Apr 03 '21 at 13:30
  • 1
    @batthomas - Suggestion: ever (**ever**) put the implementation of templates (classes/structs, functions, methods) in the header. Isn't strictly necessary but usually avoid a lot of troubles. More info in [this answer](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – max66 Apr 03 '21 at 14:03