std::enable_if 不能用于禁用此声明

std::enable_if cannot be used to disable this declaration

我有一段相当复杂的代码,我将其简化为这个复制器:

#include <type_traits>
#include <tuple>
template<typename ...As>
struct outer {
    template<typename ...Bs>
    struct inner {
        template<bool dummy, typename E = void>
        struct problem;
        using TA = std::tuple<As...>;
        using TB = std::tuple<Bs...>;

        template<bool dummy>
        struct problem<dummy, typename std::enable_if<std::tuple_size<TA>::value < std::tuple_size<TB>::value>::type>
        {
            static constexpr auto val() { return 1; } // actually a complex function
        };

        template<bool dummy>
        struct problem<dummy, typename std::enable_if<std::tuple_size<TA>::value >= std::tuple_size<TB>::value>::type>
        {
            static constexpr auto val() { return 0; }
        };
    };
};

int main() {
    return outer<int, float>::inner<double>::problem<false>::val();
}

它无法编译(使用 gcc 或 clang),说:

<source>:13:82: error: failed requirement 'std::tuple_size<std::tuple<int, float> >::value < std::tuple_size<std::tuple<double> >::value'; 'enable_if' cannot be used to disable this declaration

        struct problem<dummy, typename std::enable_if<std::tuple_size<TA>::value <std::tuple_size<TB>::value>::type>

                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~

<source>:27:31: note: in instantiation of template class 'outer<int, float>::inner<double>' requested here

    return outer<int, float>::inner<double>::problem<false>::val();

我尝试了一些变体,但没有任何效果。

我阅读了一些已经发布的问答,例如: 但他们似乎没有回答我的问题。

PS :我可以使用 C++17,但这必须适用于任何编译器。

建议:尝试如下操作

struct inner {
    using TA = std::tuple<As...>;
    using TB = std::tuple<Bs...>;

    template<bool dummy, typename UA = TA, typename E = void>
    struct problem;

    template<bool dummy, typename UA>
    struct problem<dummy, UA,
       std::enable_if_t<(std::tuple_size_v<UA> < std::tuple_size_v<TB>)>>
     { static constexpr auto val() { return 1; } };

    template<bool dummy, typename UA>
    struct problem<dummy, UA,
       std::enable_if_t<(std::tuple_size_v<UA> >= std::tuple_size_v<TB>)>>
     { static constexpr auto val() { return 0; } };
};

我的意思是...考虑到 SFINAE 可以对您想要的 struct/class(或函数或方法)的模板参数进行测试 enable/disable。

您的原始代码中的问题是 SFINAE 测试仅考虑 TATB,它们是包含 probleminner 结构中定义的类型。因此测试仅依赖于外部模板参数(As...Bs...),而不依赖于 problem.

的模板参数

添加具有默认值的模板参数 problem

// ..................VVVVVVVVVVVVVVVVV
template<bool dummy, typename UA = TA, typename E = void>
struct problem;

不改变problem本身的实际使用,只是改造std::enable_if

中的测试
template<bool dummy, typename UA>
struct problem<dummy, UA, // ..........VV  UA, not TA
   std::enable_if_t<(std::tuple_size_v<UA> < std::tuple_size_v<TB>)>>
 { static constexpr auto val() { return 1; } };

在涉及 problem 本身的模板参数的测试中。

如评论中所建议,使用 if constexpr(C++17 的一部分)使代码更简单:

template<typename ...As>
struct outer {
    template<typename ...Bs>
    struct inner {
        using TA = std::tuple<As...>;
        using TB = std::tuple<Bs...>;

        struct problem
        {
            static constexpr auto val()
            {
                if constexpr (std::tuple_size<TA>::value < std::tuple_size<TB>::value)
                    return 1; // Complex function goes here
                else
                    return 0; // Other complex function (?) goes here
            }
        };
    };
};

Demo

正如@unimportant 评论的那样:if-constexpr 自 C++17 以来。允许您摆脱 dummy 和更多行:

#include <type_traits>
#include <tuple>

template<typename ...As>
struct outer {
    template<typename ...Bs>
    struct inner {
        using TA = std::tuple<As...>;
        using TB = std::tuple<Bs...>;

        static constexpr auto val() { 
            if constexpr (std::tuple_size_v<TA> >= std::tuple_size_v<TB>) {
                return 0;
            }
            else {
                return 1;
            }
        }
    };
};

int main() {
    return outer<int, float>::inner<double>::val();
}

The program '[4544] main.exe' has exited with code 0 (0x0).