c++ - 用于检查所有模板参数类型是否唯一的编译时 C++ 函数

标签 c++ overloading variadic-templates multiple-inheritance c++20

有一个很好的问题 ( Which substitution failures are not allowed in requires clauses? ) 提出了下一个问题。
需要编写一个编译时函数template<typename... Ts> constexpr bool allTypesUnique()将返回 true如果所有参数类型都是唯一的,并且 false除此以外。并且限制不是成对比较参数类型。不幸的是,答案仅解释了为什么不能用某些特定方法实现这样的功能。
我认为可以使用多重继承来实现解决方案。这个想法是让一个类继承自多个类:每个类型一个 TTs .每个这样的类都定义了一个带有依赖于 T 的签名的虚函数。 .如果一些 TTs 中被发现不止一次然后函数 f在子类中将覆盖基类中的函数,它可以被检测到:

template<typename> struct A{};

template<typename T, typename... Ts>
struct B : B<Ts...> {
    using B<Ts...>::f;
    constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
    int count = 0;
};

template<typename T>
struct B<T> {
    constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
    int count = 0;
};

template<typename... Ts>
constexpr bool allTypesUnique() {
    B<Ts...> b;
    bool res = true;
    ( b.f( A<Ts>{}, res ), ... );
    return res;
}

int main() {
    static_assert( allTypesUnique<void>() );
    static_assert( allTypesUnique<void, int&>() );
    static_assert( !allTypesUnique<int&, int&>() );
    static_assert( allTypesUnique<char, short, int>() );
    static_assert( !allTypesUnique<char, short, char>() );
}
演示:https://gcc.godbolt.org/z/8jhnE7P11
只是好奇,解决方案是否正确,是否有针对此问题的更简单的解决方案?

最佳答案

如果您根据每个给定的类型使用虚拟基类,那么对于结果类中的每个唯一类型,您将获得精确的一个基类实例。如果给定类型的数量是生成的基类的数量,则每个类型都是唯一的。您可以通过其大小“测量”生成的基类的数量,但必须注意您有一个 vtable 指针,其中的大小取决于实现。因此,每个生成的类型应该足够大以隐藏对齐问题。
顺便说一句:它也适用于引用类型。


template < typename T> struct AnyT { char i[128]; };

template < typename FIRST, typename ... T>
struct CheckT: virtual AnyT<FIRST>, virtual CheckT<T...> { };

template < typename FIRST >
struct CheckT<FIRST>: virtual AnyT<FIRST> {};


template < typename ... T>
constexpr bool allTypesUnique()
{
    using T1 = CheckT<int>;
    using T2 = CheckT<bool, int>;

    constexpr std::size_t s1 = sizeof( T1 );
    constexpr std::size_t s2 = sizeof( T2 );
    constexpr std::size_t diff = s2 - s1; 
    constexpr std::size_t base = s1 - diff;
    constexpr std::size_t measure = sizeof( CheckT< T...> );

    return !((sizeof...(T)*diff+base) - measure);
}


int main() {
    static_assert( allTypesUnique<void>() );
    static_assert( allTypesUnique<void, int>() );
    static_assert( !allTypesUnique<void, void>() );
    static_assert( allTypesUnique<char, short, int>() );
    static_assert( !allTypesUnique<char, short, char>() );
}
Demo

关于c++ - 用于检查所有模板参数类型是否唯一的编译时 C++ 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69236476/

相关文章:

c++ - 楼主绘制的任务栏缩略图预览

c++ - 潜在 throw 函数是否信号安全?

scala - 无法为重载方法创建 ScalaDoc 链接

c++ - 模板推导计算为相同函数的重载

c++ - 模板包扩展以将函数应用于连续的参数对

c++ - 双重分派(dispatch)的循环依赖

c++ - 创建只读不可删除文件

C++输入重载陷入while循环

c++ - 使用 std::index_sequence 初始化具有固定大小数组成员的 POD 结构容器

c++ - 如何使用 C++11 可变参数模板来定义由 vector 元组支持的元组 vector ?