【问题标题】:Clang complains about undefined constexpr function in unevaluated contextClang 在未评估的上下文中抱怨未定义的 constexpr 函数
【发布时间】:2016-08-17 13:18:00
【问题描述】:

我正在使用一个简单的 SFINAE 技巧来检查成员函数是否存在,如下所示:

#include <type_traits>

template <typename C>
struct has_size {
    template <typename T>
    static constexpr auto check(T*) ->
        decltype(std::declval<T const>().size(), std::true_type{});

    template <typename>
    static constexpr auto check(...) -> std::false_type;

    static constexpr bool value = decltype(check<C>(nullptr))::value;
};

// Usage:
static_assert(has_size<std::vector<int>>::value, "std::vector<int> has size()");

(我现在知道there’s a simpler method,但是当我写这段代码时还没有回来。)

此代码适用于 GCC。然而,Clang 发出警告1(Apple LLVM 7.3 之前的所有版本,以上游为准):

decltype.cpp:15:27: error: inline function 'has_size<std::__1::vector<int, std::__1::allocator<int> > >::check<std::__1::vector<int, std::__1::allocator<int> > >' is not defined [-Werror,-Wundefined-inline]
    static constexpr auto check(T*) ->
                      ^
decltype.cpp:22:44: note: used here
    static constexpr bool value = decltype(check<C>(nullptr))::value;

换句话说,clang 期望函数被定义,而不仅仅是声明,即使它们从未被调用(仅在 decltype 的未评估上下文中)。

这是 clang 的错误吗?还是抱怨是对的?如果是这样,GCC 是否也正确地接受了这个代码?

此外,在写这个问题时,我意识到可以通过删除成员函数模板前面的constexpr 限定符来完全避免clang 编译错误。 constexpr 的存在在这里有什么变化?


1 这是一个问题,因为我正在使用 -Werror 进行编译。有一些警告是基于启发式的,因此存在不可避免的误报,但据我所知,情况并非如此。

【问题讨论】:

    标签: c++ constexpr clang++


    【解决方案1】:

    如果您不打算调用一个函数,那么标记它constexpr 是没有意义的。

    函数上的constexpr 对类型系统不可见(嗯,除了 C++14 之前的版本之外,它具有创建非静态成员函数 const 的副作用);相反,它承诺对于模板类型参数和函数参数的至少一个组合(以及对象状态,对于非静态成员函数),函数的主体可以作为常量表达式求值 (或等效于常量表达式的算法)。相反,在函数上缺少constexpr 是对编译器的指示,它甚至不尝试将函数体作为常量表达式求值。

    Clang 不是 正确,确切地说,但它也不是 不正确,因为您明确要求它拒绝有效程序(-Werror )。您应该将警告错误视为一个强烈的提示,即没有定义的 constexpr 函数是一个坏主意。

    【讨论】:

    • 是的,完全同意。我创建这些函数constexpr 的事实没有任何意义。我只是对它似乎改变了未评估的上下文看待它们的方式感到困惑。
    【解决方案2】:

    这是 clang 的错误吗?还是抱怨是对的?如果是这样,GCC是否也正确 接受此代码?

    此外,在写这个问题时,我意识到 clang 编译 通过删除前面的 constexpr 限定符可以完全避免错误 成员函数模板。 constexpr的存在有什么变化 在这里?

    编译器警告超出 C++ 标准。对包含人为错误指示的有效程序发出警告。在您的特定情况下,您选择使用 constexpr 限定您未定义的函数。仅当您从不调用该函数时,使用该类的程序才有效。如果确实如此,则不需要constexpr。但是,如果您打算调用该函数(尽管忘记为其提供实现),但由于一些错误(复杂的重载解决方案,或者只是一个愚蠢的错字),调用了不同的函数呢?

    因此,Clang 发出警告有其意义。然而,这种情况是否值得警告是有争议的。我个人不会针对 GCC 提交错误。

    【讨论】:

    • 警告是在调用站点(不是调用站点)生成的,这就是让我怀疑这是一个错误的原因:clang 似乎认为我将调用该函数。
    • 呼叫站点不一定会生成警告。示例:godbolt.org/g/GbWxNp
    • 我知道,但在这种情况下它是。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多