Detect if a type is a std::tuple?

后端 未结 5 943
天涯浪人
天涯浪人 2020-12-31 05:01

Currently I have two functions :

template bool f(Type* x);
template bool f(std::tuple* x);


        
相关标签:
5条回答
  • 2020-12-31 05:12

    Sure, using is_specialization_of (link taken and fixed from here):

    template<typename Type, bool IsTuple = is_specialization_of<Type, std::tuple>::value>
    bool f(Type* x);
    

    The question is, however, do you really want that? Normally, if you need to know if a type is a tuple, you need special handling for tuples, and that usually has to do with its template arguments. As such, you might want to stick to your overloaded version.

    Edit: Since you mentioned you only need a small portion specialized, I recommend overloading but only for the small special part:

    template<class T>
    bool f(T* x){
      // common parts...
      f_special_part(x);
      // common parts...
    }
    

    with

    template<class T>
    void f_special_part(T* x){ /* general case */ }
    
    template<class... Args>
    void f_special_part(std::tuple<Args...>* x){ /* special tuple case */ }
    
    0 讨论(0)
  • 2020-12-31 05:19

    With C++17, here is a fairly simple solution using if constexpr

    template <typename> struct is_tuple: std::false_type {};
    
    template <typename ...T> struct is_tuple<std::tuple<T...>>: std::true_type {};
    

    Then you can do something like:

    template<typename Type> bool f(Type* x) {
        if constexpr (is_tuple<Type>::value) {
            std::cout << "A tuple!!\n";
            return true;
        }
    
        std::cout << "Not a tuple\n";
        return false;
    }
    

    A test to ensure it worked:

    f(&some_tuple);
    f(&some_object);
    

    Output:

    A tuple!!
    Not a tuple


    Solution taken in part from an answer found here: How to know if a type is a specialization of std::vector?

    0 讨论(0)
  • 2020-12-31 05:19

    You could just have your functions defer to another function:

    template<typename Type,bool IsTuple> bool f(Type *x);
    
    template<typename Type> 
    inline bool f(Type* x) { return f<Type,false>(x); }
    
    template<typename... List> 
    inline bool f(std::tuple<List...>* x) { return f<std::tuple<List...>,true>(x); }
    
    0 讨论(0)
  • 2020-12-31 05:22

    Might be a little late but you can also do something like this, in a more modern c++17 style with template variables:

    template <typename T>
    constexpr bool IsTuple = false;
    template<typename ... types>
    constexpr bool IsTuple<std::tuple<types...>>   = true;
    

    And some tests

    struct TestStruct{};
    
    static_assert(IsTuple<int> == false,                "Doesn't work with literal.");
    static_assert(IsTuple<TestStruct> == false,         "Doesn't work with classes.");
    static_assert(IsTuple<std::tuple<int, char>>,       "Doesn't work with plain tuple.");
    static_assert(IsTuple<std::tuple<int&, char&>>,     "Doesn't work with lvalue references");
    static_assert(IsTuple<std::tuple<int&&, char&&>>,   "Doesn't work with rvalue references");
    

    You can view it here https://godbolt.org/z/FYI1jS

    EDIT: You will want to run std::decay, std::remove_volatile, std::remove_const to handle special cases.

    0 讨论(0)
  • 2020-12-31 05:23

    With C++11, this is my preferred pattern:

    // IsTuple<T>()
    template <typename T>
    struct IsTupleImpl : std::false_type {};
    
    template <typename... U>
    struct IsTupleImpl<std::tuple <U...>> : std::true_type {};
    
    template <typename T>
    constexpr bool IsTuple() {
      return IsTupleImpl<decay_t<T>>::value;
    }
    

    Works great. No dependencies (I can't use Boost).

    0 讨论(0)
提交回复
热议问题