c++ - 检查可变参数模板参数的唯一性

标签 c++ c++11 variadic-templates typetraits

我希望可变参数模板参数必须是唯一的。 我知道什么时候多继承,相同的类继承是不允许的。

struct A{};
struct B: A, A{}; // error

使用这个规则,我做了一点代码。

#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.
}

但我的程序没有按预期运行。怎么了?

//更新: //谢谢,我修复了我的错误: //

//     #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.
//        }
//

问:谁能解释一下,为什么会失败?

UPDATE2:我之前的更新是非法的 :))。合法的形式,但它编译了 O(N) 时间。

#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;

}

最佳答案

传递指向 base_all<U...> 的指针只需要存在 base_all<U...> 的声明.如果不尝试访问定义,编译器将不会检测到该类型实际上是错误定义的。缓解该问题的一种方法是使用需要定义 base_all<U...> 的参数。 ,例如:

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;
}

虽然上面回答了这个问题,但它无法编译:创建的多重继承不在 SFINAE 考虑的合适上下文中。我认为您不能利用不允许从两次继承的相同基数的规则。不过,相关测试可以采用不同的方式实现:

#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 , "!");
}

关于c++ - 检查可变参数模板参数的唯一性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18986560/

相关文章:

c++ - C++ 中 std::resize(n) 和 std::shrink_to_fit 的区别?

c++ - 使用位域转换大型项目以使用更便携的东西

c++ - 为什么要使用已删除的右值引用构造函数?

templates - 将可变参数模板转换为函数调用的线性编译时算法

c++ - 重载函数内部的函数重载

c++ - 如何向 CMake 提供 vcpkg 信息?

c++ - 如何专用于模板模板参数

c++ - 相互比较文本文件的元素

c++ - 在 C++ 中填充 C 结构的填充字节? (不涉及结构包装!)

c++ - 有没有办法提取模板的参数列表以放入另一个元函数?