c++ - Clang 提示未评估的上下文中未定义的 constexpr 函数

标签 c++ constexpr clang++

我正在使用一个简单的 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 进行编译。有一些警告是基于启发式的,因此存在不可避免的误报,但据我所知,这里的情况并非如此。

最佳答案

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

函数上的

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

Clang 确实不正确,但也不是不正确,因为您已经明确要求它拒绝有效程序(使用 -错误)。您应该将 warning-error 视为一个强烈的提示,即没有定义的 constexpr 函数不是一个好主意。

关于c++ - Clang 提示未评估的上下文中未定义的 constexpr 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38997828/

相关文章:

c++ - 我应该尝试返回一个数组,还是有更好的解决方案?

c# - 拦截与获取Windows版本相关的API调用

c++ - Lint:调用函数 'memcpy(void *, const void *, std::size_t)' 违反语义 '(3n>4)'

c++ - constexpr 对于重载有用吗

c++ - 代码中未调用的函数在运行时被调用

c++ - 为套接字轮询/选择设置超时值的最佳做法是什么?

c++ - constexpr 构造函数和函数

c++ - constexpr 构造函数中不能使用 constexpr 构造函数

c++ - 删除了隐式声明的复制赋值运算符

c++ - 有没有办法用 clang 有效地编译已经预处理的文件?