How can I make this variadic template code shorter using features from C++14 and C++1z?

前端 未结 4 1563
[愿得一人]
[愿得一人] 2020-12-11 02:55

This is a code snippet that I am going to use in order to check whether the variadic template types are unique:

template 
struct is_one_of         


        
相关标签:
4条回答
  • 2020-12-11 03:25
    #include <type_traits>
    
    template <typename F, typename... Ts>
    constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...);
    
    template <typename...>
    constexpr bool is_unique = true;
    
    template <typename F, typename... Ts>
    constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>;
    

    DEMO

    0 讨论(0)
  • 2020-12-11 03:31

    I'd (now) suggest using the std::conj/disj/nega family of STL functions:

    #include <type_traits>
    
    template <typename H, typename... T>
    struct is_one_of : std::disjunction<std::is_same<H, T>...> {};
    
    template <typename H, typename... T>
    struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {};
    
    template <typename H>
    struct is_unique<H> : std::true_type {};
    
    int main()
    {
        static_assert(is_one_of<int, char, double, int, bool>::value);
        static_assert(is_unique<int, char, double, bool>::value);
        static_assert(!is_unique<int, int, char, double, bool>::value);
    }
    

    When fold-expressions, which were designed for these cases, are released into the language this will become trivial:

    namespace stx = std::experimental;
    
    template <typename H, typename... T>
    struct is_one_of {
        static constexpr bool value = (stx::is_same_v<H, T> || ...);
    };
    
    template <typename H, typename... T>
    struct is_unique {
        static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value);
    };
    
    template <typename H>
    struct is_unique<H> : std::true_type {};
    
    0 讨论(0)
  • 2020-12-11 03:36

    We recently added std::disjunction to the C++1z draft, which can be used for is_one_of (and it stops instantiating as soon as it finds a match, see the link for more details):

    template <typename F, typename... T>
      using is_one_of = std::disjunction<is_same<F, T>...>;
    

    This is already implemented in GCC trunk. For older versions of GCC you can use the implementation detail __or_ instead:

    template <typename F, typename... T>
      using is_one_of = std::__or_<is_same<F, T>...>;
    

    Or implement disjunction by hand using C++11 facilities, as shown at the end of the proposal linked to above.

    0 讨论(0)
  • 2020-12-11 03:43

    I'm in line with Brian Rodriguez's and Piotr Scontnincki's answers, as far as it concerns the fold expressions part. Until folding expressions are in, you could shrink the existing code a little bit by getting rid of the incomplete primary templates as follows:

    template <typename...>
    struct is_one_of {
        static constexpr bool value = false;
    };
    
    template <typename F, typename S, typename... T>
    struct is_one_of<F, S, T...> {
        static constexpr bool value =
            std::is_same<F, S>::value || is_one_of<F, T...>::value;
    };
    
    template <typename...>
    struct is_unique {
        static constexpr bool value = true;
    };
    
    template <typename F, typename... T>
    struct is_unique<F, T...> {
        static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value;
    };
    
    0 讨论(0)
提交回复
热议问题