Clang在未评估的上下文中抱怨未定义的constexpr函数

时间:2016-08-17 13:18:00

标签: 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进行编译。有一些警告是基于启发式的,因此有不可避免的误报,但据我所知,情况并非如此。

2 个答案:

答案 0 :(得分:2)

  

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

     

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

编译器警告不在C ++标准之内。对包含人为错误迹象的有效程序发出警告。在您的特定情况下,您选择使用constexpr您未定义的函数进行限定。只有在您从未调用该函数时,使用该类的程序才有效。如果确实如此,则不需要constexpr。但是如果你打算调用那个函数(虽然忘了为它提供一个实现),但是由于一些错误(复杂的重载解析,或者只是一个愚蠢的错误),会调用另一个函数呢?

因此,Clang有责任发出警告。但是,这种情况是否值得警告是有争议的;我个人不会对GCC提出错误。

答案 1 :(得分:2)

如果您不想打电话给某个功能,那就没有必要标记它constexpr

函数的

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

Clang完全不是正确的,但它不是不正确的,因为你特别要求它拒绝有效的程序({{1} }})。您应该将警告错误视为一个强烈提示,-Werror没有定义的函数是个坏主意。