I want variadic template parameters must unique. I know when multi inheritance, identical classes inheritance is not allowed.
struct A{};
struct B: A, A{}; // error
Using this rule, I made a little code.
#include <type_traits>
template< class T> struct id{};
template< class ...T> struct base_all : id<T> ... {};
template< class ... T>
struct is_unique
{
     template< class ... U>
 static constexpr bool test( base_all<U...> * ) noexcept { return true; }
template< class ... U>
static constexpr bool test( ... ) noexcept { return false;}
static constexpr bool value = test<T...>(0);
};
int main()
{
    constexpr bool b = is_unique<int, float, double>::value; // false -- Why?
    constexpr bool c = is_unique< int, char, int>::value; // false
   static_assert( b == true && c == false , "!");// failed.
}
But my program is not worked as I expected. What's wrong?
//UPDATE: //Thanks, I fix my error: //
//     #include <type_traits>
//     #include <cstddef>
//    
//     template< class ... U> struct pack{};
//    
//     template< class T> struct id{};
//     template< class T> struct base_all;
//     template< class ... T> struct base_all< pack<T...> > : id<T>  ... {};
//        
//     
//    
//     template< class ... T>
//     struct is_unique
//     {
//           template< class P,  std::size_t  =  sizeof(base_all<P>) >
//          struct check;
//     
//       template< class ...U>
//      static constexpr bool test(check< pack<U...> > * ) noexcept { return true;}
//        
//        template< class ... U>
//        static constexpr bool test(...)noexcept { return false;}
//        
//        static constexpr bool value =  test<T...>(0);
//        };
//        
//        int main()
//        {
//            constexpr bool b = is_unique<int, float, double>::value; // true
//            constexpr bool c = is_unique< int, char, int>::value; // false
//             
//          static_assert( b == true && c == false , "!");// success.
//        }
//
Q: somebody can explain, why it's failed?
UPDATE2: My previous update was illegal :)). Legal form, but it compiled O(N) time.
#include <cstddef>
#include <iostream>
#include <type_traits>
namespace mpl
{
template< class T > using invoke = typename T :: type ;
template< class C, class I, class E > using if_t     = invoke< std::conditional< C{}, I, E> >;
template< class T > struct id{};
struct empty{};
template< class A, class B > struct base : A, B {};
template< class B , class ... > struct is_unique_impl;
template< class B > struct is_unique_impl<B>: std::true_type{};
template< class B, class T, class ... U>
struct is_unique_impl<B, T, U...> : if_t< std::is_base_of< id<T>, B>, std::false_type, is_unique_impl< base<B,id<T>>, U...> >{};
template< class ...T >struct is_unique : is_unique_impl< empty, T ... > {};
} // mpl    
int main()
{
    constexpr bool b = mpl::is_unique<int, float, double>::value;
    constexpr bool c = mpl::is_unique< int, char, int > :: value;
    static_assert( b == true   , "!");
    static_assert( c == false, "!");
    return 0;
}
                Passing a pointer to base_all<U...> merely requires the existence of a declaration of base_all<U...>. Without attempting the to access the definition, the compiler won't detect that the type is actually ill-defined. One approach to mitigate that problem would be to use an argument which requires a definition of base_all<U...>, e.g.:
template< class ...T> struct base_all
   : id<T> ...
{
    typedef int type;
};
// ...
template< class ... U>
static constexpr bool test(typename base_all<U...>::type) noexcept
{
    return true;
}
Although the above answers the question, it fail to compile: the multiple inheritance created isn't in a suitable context to be considered for SFINAE. I don't think you can leverage the rule on not allowing the same base inherited from twice. The relevant test can be implemented differently, though:
#include <type_traits>
template <typename...>
struct is_one_of;
template <typename F>
struct is_one_of<F>
{
    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;
template <>
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;
};
int main()
{
    constexpr bool b = is_unique<int, float, double>::value;
    constexpr bool c = is_unique< int, char, int>::value;
    static_assert( b == true && c == false , "!");
}
                        Using C++17, you can use fold expressions. Especially with larger numbers of template parameters, this version can be orders of magnitude faster (and less memory hungry) than the other solutions presented here:
#include <type_traits>
template <typename T> 
struct Base{};
template <typename... Ts>
struct TypeSet : Base<Ts>...
{     
   template<typename T>
   constexpr auto operator+(Base<T>)
   {
      if constexpr (std::is_base_of_v<Base<T>, TypeSet>)
        return TypeSet{};
      else
        return TypeSet<Ts..., T>{};
   }
   constexpr auto size() const -> std::size_t
   {
      return sizeof...(Ts);
   }
};
template<typename... Ts>
constexpr auto are_unique() -> bool
{ 
   constexpr auto set = (TypeSet<>{} + ... + Base<Ts>{});
   return set.size() == sizeof...(Ts);
}
int main()
{
   static_assert(are_unique<int, float, char, char*>());
   static_assert(not are_unique<int, float, char, char>());
}
See https://godbolt.org/z/_ELpyJ
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With