Is it possible to check for existence of member templates just by an identifier?

后端 未结 4 960
醉酒成梦
醉酒成梦 2021-01-04 11:54

Can we detect member function template, variable template, class/struct/union template or alias templ

相关标签:
4条回答
  • 2021-01-04 12:07

    This approach works in the presence of multiple overloads, returning false_type if and only if there are no methods, or members, called bar. It doesn't tell us anything useful about what the bar(s) is/are though (more on that later).

    (Note: This answer (and question?) are dupes. I learned about this technique on SO only a few days ago. But I can't find the original!)

    This uses void_t, which you may need to define yourself (not in c++11, for example):

    template<typename ...T>
    struct voider { using type = void; };
    template<typename ...T>
    using void_t = typename voider<T...> :: type;
    

    bar is the member we are interested in, so we make a really boring struct with a member called bar:

    struct just_a_bar { int bar; };
    

    Then a template, given T, which declares a struct that inherits from both T and just_a_bar.

    template<typename T>
    struct MultipleBars : public T , public just_a_bar { };
    

    Now, decltype(MultipleBars<T>::bar) will give an ambiguity error if, and only if, there is a member bar in T. We can use this:

    template<typename T, typename =void>
    struct has_at_least_one_bar : public true_type {};
    
    template<typename T>
    struct has_at_least_one_bar<T, void_t< decltype(MultipleBars<T>::bar) >>
        : public false_type { 
    };
    

    Then, to use the above for real:

    struct zero { };
    struct one { 
        void bar(int,int);
    };
    struct two { 
        //template<typename P, typename Q> // works fine with templates too
        void bar(int);
        void bar(int,int);
    };
    
    
    int main() { 
        cout << boolalpha;
        cout << has_at_least_one_bar<zero>{} << endl; // false
        cout << has_at_least_one_bar<one>{} << endl;  // true
        cout << has_at_least_one_bar<two>{} << endl;  // true
    }
    

    Once you know bar exists, you probably want more detail. If you have a few specific patterns in mind (non-template member, template method with type parameters only, template method with two int non-type parameters, template method with three template-template parameters, ...) then I think you can test for each of those patterns individually. But ultimately there are limits to what you can detect with a finite number of such patterns. (And the fact that you mean templated methods, not templated structs, might make this more difficult

    0 讨论(0)
  • 2021-01-04 12:09

    I can show you how to detect a struct template:

    template < class > struct check_template : std::false_type {};
    
    // Specialize for template classes
    template <template<class...> class X, class... Args>
    struct check_template< X<Args...> > : std::true_type {};
    

    You can then probably play around with declval, void_t, etc. to detect member templates.

    In case you want to detect types vs. meta-types, i.e. templates like std::vector and not std::vector<int>, you can do the following:

    #include <iostream>
    
    template <template<class...> class>
    constexpr bool is_template()
    {
        return true;
    }
    
    template <class>
    constexpr bool is_template()
    {
        return false;
    }
    
    struct Foo{};
    
    template<class>
    struct TemplateFoo{};
    
    int main()
    {
         std::cout << std::boolalpha;
         std::cout << is_template<Foo>() << std::endl;
         std::cout << is_template<TemplateFoo>() << std::endl;
    }
    

    Live on Coliru

    Note that the solutions won't work if the meta-type has any non-type parameters, like

    template<class, int> struct X{};
    
    0 讨论(0)
  • 2021-01-04 12:10

    I think I got it. Thanks to Aaron McDaid and vsoftco answers, I succeeded in detecting member type templates (alias template, struct template, class template and union template), member function templates with one additional drawback, and member variable templates.

    This implementation has some drawbacks:

    • Class foo that we check for existence of name bar musn't be final type.
    • Templates with mixed type/non-type/template-template parameters won't be detected.
    • Code is kinda long.

    Additional drawback is:

    • [Note: Will be fixed soon!] Checking for member function tempalates will return true, if class foo has any overloaded function bar. I just didn't have any means to detect overloaded function alone. This will also affect final has_member_template type trait.

    Here is the implementation:

    #include <iostream>
    #include <type_traits>
    #include <iomanip>
    
    /***Check if type is template***/
    template <template<class...> class>
    constexpr bool is_template_type()
    {
        return true;
    }
    
    template <class>
    constexpr bool is_template_type()
    {
        return false;
    }
    
    /***Check if T has static member function "bar" ***/
    template <class, class = void>
    struct has_static_member_function_bar : std::false_type
    { };
    
    template <class T>
    struct has_static_member_function_bar<T,
        std::enable_if_t<std::is_function<typename std::remove_pointer<decltype(&T::bar)>::type>::value
            >
        > : std::true_type
    { };
    
    /***Check if T has member function "bar" ***/
    template <class, class = void>
    struct has_member_function_bar : std::false_type
    { };
    
    
    template <class T>
    struct has_member_function_bar<T,
        std::enable_if_t<std::is_member_function_pointer<decltype(&T::bar)>::value
            >
        > : std::true_type
    { };
    
    /***Check if T has member reference "bar" ***/
    template <class, class = void>
    struct has_member_reference_bar : std::false_type
    { };
    
    template <class T>
    struct has_member_reference_bar<T,
        std::enable_if_t<std::is_reference<decltype(T::bar)>::value
            >
        > : std::true_type
    { };
    
    /***Check if T has static member object "bar" ***/
    template <class, class = void>
    struct has_static_member_object_bar : std::false_type
    { };
    
    template <class T>
    struct has_static_member_object_bar<T,
        std::enable_if_t<std::is_object<typename std::remove_pointer<decltype(&T::bar)>::type>::value &&
                        (!std::is_member_object_pointer<decltype(&T::bar)>::value)
    
            >
        > : std::true_type
    { };
    
    /***Check if T has member function "bar" ***/
    template <class, class = void>
    struct has_member_object_bar : std::false_type
    { };
    
    template <class T>
    struct has_member_object_bar<T,
        std::enable_if_t<std::is_member_object_pointer<decltype(&T::bar)>::value
            >
        > : std::true_type
    { };
    
    /***Check if T has member alias, struct, class, union template "bar" ***/
    template <class, class = void>
    struct has_member_type_template_bar : std::false_type
    { };
    
    template <class T>
    struct has_member_type_template_bar<T,
        std::enable_if_t<is_template_type<T::template bar>()
            >
        > : std::true_type
    { };
    
    /***Check if T has at least one name "bar" ***/
    struct has_at_least_one_bar_impl { int bar; };
    
    template<typename T>
    struct bar_overloads : T , has_at_least_one_bar_impl { };
    
    template<typename T, typename = void>
    struct has_at_least_one_bar : std::true_type { };
    
    template<typename T>
    struct has_at_least_one_bar<T, std::void_t< decltype(bar_overloads<T>::bar) >>
        : std::false_type { };
    
    /***Check if T has member object, reference, not-overloaded function "bar" ***/
    template <class, class = void>
    struct has_non_type_non_overloaded_member_bar : std::false_type
    { };
    
    template <class T>
    struct has_non_type_non_overloaded_member_bar<T,
        std::void_t<decltype((void)(T::bar))>> : std::true_type
    { };
    
    
    /***Check if T has member function "bar" ***/
    template <class, class = void>
    struct has_type_member_bar : std::false_type
    { };
    
    template <class T>
    struct has_type_member_bar<T,
        std::void_t<typename T::bar>> : std::true_type
    { };
    
    /***Check if T has no more than one member "bar" ***/
    template<class, class = void, class = void>
    struct has_at_most_one_bar : std::false_type
    { };
    
    template<class T>
    struct has_at_most_one_bar<T,
        std::enable_if_t<
            has_type_member_bar<T>::value ||
            has_non_type_non_overloaded_member_bar<T>::value
            >
        > : std::true_type
    { };
    
    /***Check if T has member function template "bar" ***/
    template <class, class = void>
    struct has_member_function_template_bar : std::false_type
    { };
    
    template <class T>
    struct has_member_function_template_bar<T,
        std::enable_if_t<has_at_least_one_bar<T>::value &&
            (!has_member_type_template_bar<T>::value) &&
            (!has_non_type_non_overloaded_member_bar<T>::value) &&
            (!has_member_function_bar<T>::value) &&
            (!has_type_member_bar<T>::value)
            >
        > : std::true_type
    { };
    
    /***Check if T has member variable template "bar" ***/
    template <class, class = void>
    struct has_member_variable_template_bar : std::false_type
    { };
    
    template <class T>
    struct has_member_variable_template_bar<T,
        std::enable_if_t<has_at_least_one_bar<T>::value &&
            (!has_member_type_template_bar<T>::value) &&
            (!has_member_function_template_bar<T>::value) &&
            (!has_type_member_bar<T>::value) &&
            (!has_static_member_function_bar<T>::value) &&
            (!has_member_function_bar<T>::value) &&
            (!has_member_object_bar<T>::value) &&
            (!has_member_reference_bar<T>::value) &&
            (!has_static_member_object_bar<T>::value)>
        > : std::true_type
    { };
    
    /***Check if T has any member template "bar" ***/
    template <class, class = void>
    struct has_member_template_bar : std::false_type
    { };
    
    template <class T>
    struct has_member_template_bar<T,
        std::enable_if_t<has_member_type_template_bar<T>::value ||
            has_member_function_template_bar<T>::value ||
            has_member_variable_template_bar<T>::value>
        > : std::true_type
    { };
    

    Live example

    Example output:

    ---Has type template bar---
    consists_no_bar:                  false
    consists_alias:                   false
    consists_struct:                  false
    consists_class:                   false
    consists_union:                   false
    consists_variable:                false
    consists_function:                false
    consists_overloaded_func:         false
    consists_reference:               false
    consists_t_alias:                 true
    consists_t_struct:                true
    consists_t_class:                 true
    consists_t_union:                 true
    consists_t_variable:              false
    consists_t_function:              false
    consists_t_overloaded_function:   false
    consists_s_variable:              false
    consists_s_function:              false
    consists_s_overloaded_func:       false
    consists_s_t_function:            false
    consists_s_t_overloaded_function: false
    
    --Has member function template bar---
    consists_no_bar:                  false
    consists_alias:                   false
    consists_struct:                  false
    consists_class:                   false
    consists_union:                   false
    consists_variable:                false
    consists_function:                false
    consists_overloaded_func:         true // implmementation bug
    consists_reference:               false
    consists_t_alias:                 false
    consists_t_struct:                false
    consists_t_class:                 false
    consists_t_union:                 false
    consists_t_variable:              false
    consists_t_function:              true
    consists_t_overloaded_function:   true
    consists_s_variable:              false
    consists_s_function:              false
    consists_s_overloaded_func:       true // implmementation bug
    consists_s_t_function:            true
    consists_s_t_overloaded_function: true
    
    --Has member variable template bar---
    consists_no_bar:                  false
    consists_alias:                   false
    consists_struct:                  false
    consists_class:                   false
    consists_union:                   false
    consists_variable:                false
    consists_function:                false
    consists_overloaded_func:         false
    consists_reference:               false
    consists_t_alias:                 false
    consists_t_struct:                false
    consists_t_class:                 false
    consists_t_union:                 false
    consists_t_variable:              true
    consists_t_function:              false
    consists_t_overloaded_function:   false
    consists_s_variable:              false
    consists_s_function:              false
    consists_s_overloaded_func:       false
    consists_s_t_function:            false
    consists_s_t_overloaded_function: false
    
    --Has any member template bar---
    consists_no_bar:                  false
    consists_alias:                   false
    consists_struct:                  false
    consists_class:                   false
    consists_union:                   false
    consists_variable:                false
    consists_function:                false
    consists_overloaded_func:         true // implmementation bug
    consists_reference:               false
    consists_t_alias:                 true
    consists_t_struct:                true
    consists_t_class:                 true
    consists_t_union:                 true
    consists_t_variable:              true
    consists_t_function:              true
    consists_t_overloaded_function:   true
    consists_s_variable:              false
    consists_s_function:              false
    consists_s_overloaded_func:       true // implmementation bug
    consists_s_t_function:            true
    consists_s_t_overloaded_function: true
    

    I'm still sad that I couldn't detect overloaded functions... But it was fun :)

    0 讨论(0)
  • 2021-01-04 12:20

    In C++14, you can use template variables to detect if a type is a specialization:

    #include <type_traits>
    
    template<typename>
    constexpr bool is_spec = false;
    
    template<template<typename...> class T, typename... U>
    constexpr bool is_spec<T<U...>> = true;
    
    struct S {};
    template<typename> struct R {};
    
    int main() {
        static_assert(not is_spec<S>, "!");
        static_assert(is_spec<R<void>>, "!");
    }
    

    Note that it won't work if non-type parameters are involved (as an example template<int> struct R {};).

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