std :: enable_if无法用于禁用此声明

时间:2019-06-04 13:07:28

标签: c++ variadic-templates inner-classes sfinae typetraits

我有一段非常复杂的代码,我将其简化为此复制器:

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

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

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

PS:我可以使用C ++ 17,但是必须与任何编译器一起使用。

3 个答案:

答案 0 :(得分:2)

建议:尝试以下操作

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(或函数或方法)的模板参数进行测试。

原始代码中的问题是SFINAE测试仅考虑TATB,它们是在inner结构中定义的类型,其中包含problem。因此,测试仅取决于外部模板参数(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模板参数本身的测试中。

答案 1 :(得分:1)

如注释中所建议,使用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

答案 2 :(得分:1)

正如@unimportant所评论:if-constexpr自C ++ 17起。使您摆脱<div class="row"> <div class="card"> <img src="https://animatedanatomy.com/images/16-9-dummy-image6.jpg" alt="Snow" style="width:100%"> <img class="imageoverlay" src="http://barricadeprinters.com/wp-content/uploads/2018/10/16-9placeholder.png" /> </div> <div class="card"> <img src="https://animatedanatomy.com/images/16-9-dummy-image6.jpg" alt="Forest" style="width:100%"> <img class="imageoverlay" src="http://barricadeprinters.com/wp-content/uploads/2018/10/16-9placeholder.png" /> </div> <div class="card"> <img src="https://animatedanatomy.com/images/16-9-dummy-image6.jpg" alt="Forest" style="width:100%"> <img class="imageoverlay" src="http://barricadeprinters.com/wp-content/uploads/2018/10/16-9placeholder.png" /> </div> </div> <div class="row"> <div class="card"> <img src="https://animatedanatomy.com/images/16-9-dummy-image6.jpg" alt="Snow" style="width:100%"> <img class="imageoverlay" src="http://barricadeprinters.com/wp-content/uploads/2018/10/16-9placeholder.png" /> </div> <div class="card"> <img src="https://animatedanatomy.com/images/16-9-dummy-image6.jpg" alt="Forest" style="width:100%"> <img class="imageoverlay" src="http://barricadeprinters.com/wp-content/uploads/2018/10/16-9placeholder.png" /> </div> <div class="card"> <img src="https://animatedanatomy.com/images/16-9-dummy-image6.jpg" alt="Forest" style="width:100%"> <img class="imageoverlay" src="http://barricadeprinters.com/wp-content/uploads/2018/10/16-9placeholder.png" /> </div> </div>和更多行:

dummy
  

程序“ [4544] main.exe”已退出,代码为0(0x0)。