编译时检查是否有两个具有相同模板参数的模板实例化

Compiletime check if there are two template instantiations with identical template-parameter

如果我有两个不相关的模板 AB,我该如何执行编译时检查以查看是否有两个相同的参数。例如。如果我有一些参数类型 P1P2,我想让客户端实例化 A<P1>B<P2> 而不是 A<P1>B<P1> .

我有一个解决方案,使用可变参数模板Checker<typename... Xx>,必须使用相关模板实例化:

using a = A<P1>;
using b = B<P1>;
using checker = Checker<a, b>;

checker::init(); // can be empty
                 // static_assert fails here

如果每个参数 typ 都有一个唯一的 id(掩码),这就有效,因此我可以对所有掩码进行 OR,看看它们的数量是否等于 Checker 的参数包的大小。

这个解决方案不好,因为客户端可能忘记实例化Checker模板。

我想知道是否可以在后台进行更多检查?

This solution is not good because a client can forget to instatiate the Checker template.

很好的直觉 - 因此您应该阻止客户端在实例化 Checker 之前实例化 AB。您可以通过将它们提供为只能从 Checker 访问的 类型别名 来实现。

namespace detail
{
    template <typename T> struct A;
    template <typename T> struct B;
}

template <typename P0, typename P1>
struct Checker
{
    static_assert(!std::is_same_v<P0, P1>);

    using A = detail::A<P0>;
    using B = detail::B<P1>;
};

用法:

using ClientABProvider = ABProvider<foo, bar>;
using A = typename ClientABProvider::A;
using B = typename ClientABProvider::B;

using ClientABProvider = ABProvider<foo, foo>; // Error!
using A = typename ClientABProvider::A;
using B = typename ClientABProvider::B;

如果您希望 AB 由用户提供,您可以将 Checker 的类型别名作为模板 - 但这种做法违背了它的目的,因为用户已经首先访问了 AB

template <typename P0, typename P1>
struct Checker
{
    static_assert(!std::is_same_v<P0, P1>);

    template <template <typename> class XA>
    using A = XA<P0>;

    template <template <typename> class XB>
    using B = XB<P1>;
};