Home > database >  How to write a type trait that checks if tuple types are compatible with function arguments
How to write a type trait that checks if tuple types are compatible with function arguments

Time:04-23

I am trying to write a type trait that checks whether the types stored in a tuple are compatible with the arguments of a given callable.

Currently, I have 'almost working' code, shown below. However, static assert fails in the last statement with a callable that expects reference parameters (e.g. [](int&, std::string&){}), I don't really understand why it's failing. And how does one write a trait that is inclusive for this type as well?

#include <type_traits>
#include <tuple>
#include <string>

template<typename, typename>
struct is_callable_with_tuple: std::false_type {};

template<typename Func, template<typename...> class Tuple, typename... Args>
struct is_callable_with_tuple<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};

template<typename Func, typename Args>
constexpr bool is_callable_with_tuple_v = is_callable_with_tuple<Func, Args>::value;

int main() {    
    static_assert(is_callable_with_tuple_v<decltype([](int, std::string){}), std::tuple<int, std::string>>); // OK
    static_assert(is_callable_with_tuple_v<decltype([](const int&, const std::string&){}), std::tuple<int, std::string>>); // OK
    static_assert(is_callable_with_tuple_v<decltype([](int&, std::string&){}), std::tuple<int, std::string>>); // Fails
}

CodePudding user response:

You may want to modify your trait slightly:

template<typename Func, 
         template<typename...> class Tuple, 
         typename... Args>
struct is_callable_with_tuple<Func, Tuple<Args...>>: 
    std::is_invocable<Func, Args&...> {}; // <--- note &

Or not, depending on how exactly you plan to use it. If your tuple is always an lvalue, it is probably OK. If not, then you may want to specialise it for an lvalue-reference tuple type:

template<typename Func, 
         template<typename...> class Tuple, 
         typename... Args>
struct is_callable_with_tuple<Func, Tuple<Args...>&>:  // <--- note & here
    std::is_invocable<Func, Args&...> {}; // <--- and also here

template<typename Func, 
         template<typename...> class Tuple, 
         typename... Args>
struct is_callable_with_tuple<Func, Tuple<Args...>>:  // <--- note NO & here
    std::is_invocable<Func, Args...> {}; // <--- and also here

and use it like this:

is_callable_with_tuple<decltype(myfunc), decltype((mytuple))> // note double parentheses
  • Related