c++templates

Convert template arguments of a function to exact types accepted by a given type definition of a function


Given a type definition of a function, is there a way to cast the parameters received through a variadic template as an argument, to the exact types of the typedefed function?

#include <concepts>
#include <iostream>

typedef int foo(int, int);

template <typename func, typename... Args>
  requires std::invocable<func, Args &&...>
void bar(Args&&... args) {
  ((std::cout << std::forward<Args>(args)), ...);
}

int main() { bar<foo>(4, 4.1); }

In this example I check if func would be invocable with given arguments, then print the arguments that were passed. 4 and 4.1 get printed(as expected). But foo accepts int,int so the goal would be to print 4 and 4 as a result of converting args to types of parameters accepted by foo. A simple, yet functional solution would be greatly appreciated.


Solution

  • You might use template function/lambda to extract parameters of func, as follow:

    template <typename func, typename... Ts>
      requires std::invocable<func, Ts&&...>
    void bar(Ts&&... args) {
        [&]<typename R, typename... Args>(std::type_identity<R(Args...)>){
            ((std::cout << std::forward<Args>(args)), ...);
        }(std::type_identity<func>{});
    }
    

    Demo

    As it seems conversion should be more "permissive", you might replace std::forward by static_cast in some case:

    template <typename TO, typename T>
    decltype(auto) To(T&& t)
    {
        if constexpr (std::is_same_v<std::decay_t<TO>, std::decay_t<T>>) {
            return std::forward<TO>(t);
        } else {
            return static_cast<TO>(t);
        }
    }
    
    template <typename func, typename... Ts>
      requires std::invocable<func, Ts&&...>
    void bar(Ts&&... args) {
        [&]<typename R, typename... Args>(std::type_identity<R(Args...)>){
            ((std::cout << To<Args>(args)), ...);
        }(std::type_identity<func>{});
    }
    

    Demo