我需要编写第二个 SFINAE 构造函数吗?

What I need write this second SFINAE constructor?

我想在参数包中的所有类型都不同时激活带有参数包的 class。我写了一个像这样的小辅助函数,没有问题:

template<typename T, typename... Ts>
constexpr bool has_duplicate_types() {
    if constexpr (sizeof...(Ts) == 0)
        return false;
    else
        return ((std::is_same_v<std::decay_t<T>, std::decay_t<Ts>> || ...) || has_duplicate_types<Ts...>());
}

当我尝试使用 SFINAE 激活我的 class 时,我尝试了几种方法,有效的方法是:

template<typename T, typename dummy = void, typename... Ts>
struct XYZ_imp {
    XYZ_imp() {
        std::cout << "ok\n";
    }
};

template<typename T, typename... Ts>
struct XYZ_imp<T, std::enable_if_t<has_duplicate_types<T, Ts...>()>, Ts...> {
    XYZ_imp() = delete;
};

template<typename T, typename... Ts>
using XYZ = XYZ_imp<T, void, Ts...>;

但是如您所见,代码太多了。但是当我试着这样写的时候:

template<typename T, typename... Ts>
struct XYZ {
    template<typename U = T, std::enable_if_t<has_duplicate_types<U, Ts...>(), int> = 0>
    XYZ() = delete;
};

我不知道为什么它不起作用。当存在类似 XYZ<int,int> 的类型时它按预期工作并且它说构造函数被删除,但是当类型不同时 XYZ<int,double>,我得到以下错误:

no matching function for call to 'XYZ<int, double>::XYZ()'

如果我像这样编写另一个 SFINAE 构造函数:

template<typename T, typename... Ts>
struct XYZ {
    template<typename U = T, std::enable_if_t<has_duplicate_types<U, Ts...>(), int> = 0>
    XYZ() = delete;
    template<typename U = T, std::enable_if_t<!has_duplicate_types<U, Ts...>(), int> = 0>
    XYZ() {
        std::cout << "ok\n";
    }
};

它会工作,但我不知道为什么我需要写第二个并且它不会自动选择默认的一个。知道为什么吗?

If I write another SFINAE constructor like this: ... It will work, but I have no idea why I need to write 2nd one and it does not pick defaulted one without it automatically.

如果您定义任何自定义构造函数,即使该构造函数被 SFINAE 禁用,编译器也不会生成默认构造函数。

并且由于您需要编写非 =deleted 构造函数,您不妨删除 =deleted 构造函数:

template<typename T, typename... Ts>
struct XYZ
{
    template <typename U = T, std::enable_if_t<!has_duplicate_types<U, Ts...>(), int> = 0>
    XYZ()
    {
        std::cout << "ok\n";
    }
};