2021年2月7日星期日

Resolving to different types based on the argument types of a c++ template function

I'm doing some metaprogramming and I have ran into the following problem:

I have a class that takes one template parameter T, T can be assumed to be a function with an arbitary signature. The class a member variable V, that should have the type std::tuple<> if T takes no arguments or the first argument is not a std::tuple. If the first argument is an std::tuple, V should instead have the same type as first argument.

Example:

 void f() // Should resolve to std::tuple<>   void f(int) // Should resolve to std::tuple<>   void f(std::tuple<int, float>) // Should resolve to std::tuple<int, float>   void f(std::tuple<float>, int) // Should resolve to std::tuple<float>  

I have been trying something similar to this, but with no success. As it fails when indexing the first arguement on the argument free function, without selecting any of the other alternatives in spite of those being available. I'm using MSVC 2019 16.8.4

#include <functional>  #include <concepts>  namespace detail  {      template<typename... ArgTs>      struct HasArgs : public std::conditional<(sizeof... (ArgTs) > 0), std::true_type, std::false_type>::type {};  }    //!  //! Provides argument function information  //! Based on: https://stackoverflow.com/a/9065203  //!   template<typename T>  class FunctionTraits;    template<typename R, typename... Args>  class FunctionTraits<R(Args...)>  {  public:      static const size_t arg_count = sizeof...(Args);      using HasArguments = detail::HasArgs<Args...>;        using ReturnType = R;      using ArgTypes = std::tuple<Args...>;        template <size_t i>      struct arg      {          using type = typename std::tuple_element<i, std::tuple<Args...>>::type;      };  };    namespace detail  {  template <typename T>  struct is_tuple : std::false_type {};    template <typename... Args>  struct is_tuple<std::tuple<Args...>>: std::true_type {};  }    template <typename T>  concept is_tuple = requires() { detail::is_tuple<T>::value; };      class TestMemberFunctions  {  public:      static int test_f1(std::tuple<int, float>, int)      {          return 0;      }        static int test_f2(int)      {          return 0;      }      static int test_f3()      {          return 0;      }    };    template <typename CreateT> requires (!FunctionTraits<CreateT>::HasArguments::value)  std::tuple<> TypeDeductionDummyFunction();      template <typename CreateT> requires FunctionTraits<CreateT>::HasArguments::value  auto TypeDeductionDummyFunction() -> std::conditional<is_tuple<typename FunctionTraits<CreateT>::template arg<0>::type>,                                                                                                  typename FunctionTraits<CreateT>::template arg<0>::type,                                                                                                  std::tuple<>>;    template <typename T>  class SampleClass  {      decltype(TypeDeductionDummyFunction<T>()) m_member;  };    SampleClass<decltype(TestMemberFunctions::test_f1)> c1;   SampleClass<decltype(TestMemberFunctions::test_f2)> c2;   SampleClass<decltype(TestMemberFunctions::test_f3)> c3;       
https://stackoverflow.com/questions/66091831/resolving-to-different-types-based-on-the-argument-types-of-a-c-template-funct February 08, 2021 at 02:51AM

没有评论:

发表评论