首页 文章

SFINAE constexpr与std :: get

提问于
浏览
8

这是Detecting constexpr with SFINAE的后续问题 .

我想检测元组的元素(或任何可与 std::get 一起使用的元素)是否为constexpr . 所以我编写了以下助手,类似于Xeo给出的:

template<size_t> struct sfinae_true : std::true_type{};

template<size_t N, class T>
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>;

template<size_t N, class>
std::false_type check(...);

现在我的测试驱动代码:

int main()
{
    constexpr std::tuple<size_t, size_t> arg(4,5);
    typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr;
    std::cout << "is constexpr? " << is_cexpr::value << '\n';
}

但是,这总是为我打印 false !要检查由于某种原因,并不总是调用错误的重载,我注释掉了错误的重载并得到编译器错误:

注意:候选模板被忽略:替换失败[有N = 0,T = const std :: tuple]:非类型模板参数不是常量表达式自动检查(const T&arg) - > sfinae_true <(std :: get (ARG),0)>;

但是,我知道我可以调用 std::get<N>(arg) 并获得constexpr值:

template<size_t N>
class A{};

int main()
{
    constexpr std::tuple<size_t, size_t> arg(4,5);
    A<std::get<0>(arg)> a_val;
}

编译得很好 .

  • 为什么检查功能无法正确检测到constexpr-ness?

  • 如何解决这个问题?

我在Ubuntu 16.04上使用Clang 3.8.0对此进行了测试 .

edit:

作为基于Sam的回答的进一步测试,我尝试了以下形式:

template<size_t N, class T>
auto check(const T& arg)
{
    return sfinae_true<(std::get<N>(arg)*0)>();
}

这完全摆脱了逗号运算符,GCC 5.4.0编译得很好,但Clang 3.8.0仍然抱怨 . 有趣的是,Clang强调 arg 本身不是constexpr .

为什么这个问题仍然存在? constexpr函数参数的规则是什么?

1 回答

  • 3

    这看起来像编译器问题 .

    template<size_t N, class T>
    auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>;
    

    gcc无法编译:

    t.C:8:61:错误:模板参数1无效自动检查(const T&arg) - > sfinae_true <(std :: get(arg),N)>;

    但经过稍微调整后,我得到了gcc 6.1.1的预期结果:

    #include <tuple>
    #include <type_traits>
    #include <iostream>
    
    template<size_t> struct sfinae_true : std::true_type{};
    
    template<size_t N, class T>
    auto check(const T& arg)
    {
        return sfinae_true<(std::get<N>(arg),N)>();
    }
    
    template<size_t N, class>
    std::false_type check(...);
    
    int main()
    {
        constexpr std::tuple<size_t, size_t> arg(4,5);
        typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr;
        std::cout << "is constexpr? " << is_cexpr::value << '\n';
    }
    

    这导致:

    is constexpr? 1
    

    请注意,在C 11之前的常量表达式中不允许使用逗号 . 可能是那个时代遗留下来的东西......

相关问题