Search code examples
c++template-argument-deduction

Template argument deduction, Qualified-Id and performance


Suppose I have a lambda function:

std::function<void (int&& y)> lambda = [](int&& y) { std::cout << std::forward<int>(y) << std::endl; };

Having another function named gate which takes the lambda function as arg:

template<typename T> void gate(T&& x, std::function<void (T&&)> f) { f(std::move(x)); };

as the template argument deduction cannot make equal the types lambda(0) and std::function<void (T&&)>, Indeed, I specifically need to pass the std::function<void (T&&)> directly to through gate function, a commonly used solution is to make the lambda function parameter as non-deduced context. The scope is achieved using some struct which takes in some arbitrary type and spit it right back out. Hence, template argument deduction fails and the type of 'T&&' is deducted elsewhere, in this case from the first argument passed which type was correctly deducted.

template typename<T> struct Identity { typedef T type };

template<typename T> void gate(T&& x, typename Identity<std::function<void (T&&)>>::type f) { f(std::move(x)); };

int main() { gate(1234, [](int&& y) { std::cout << std::forward<int>(y) << std::endl; }); }

What I am wondering is, are there some lost in performance given the usage of the 'identity' struct? Could this be made better? Is creating firstly lambda and then pass it as argument the better way?


Solution

  • What I am wondering is, are there some lost in performance given the usage of the 'identity' struct?

    Certainly no runtime performance because the structure is never instantiated or used.

    Compilation speed could be affected since the compiler has to instantiate that type but it "amortizes" together with the instantiation of the function template itself since there is 1:1 correspondence. It will highly depend on the compiler how quickly it can throw those instantiations away.

    FYI there is std::type_identity in C++20 for exactly this purpose which might allow the compiler to improve its performance. Maybe it will get similar treatment how Clang 15 now treats std::forward and others as builtins instead of instantiating them.