我正在使用一个简单的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
进行编译。有一些警告是基于启发式的,因此有不可避免的误报,但据我所知,情况并非如此。
答案 0 :(得分:2)
这是clang中的错误吗?或抱怨是对的吗?如果是这样,GCC也是正确的 接受此代码?
此外,在写这个问题时,我意识到了铿锵编译 通过删除前面的
constexpr
限定符可以完全避免错误 成员函数模板。constexpr
的存在会发生什么变化 这里吗?
编译器警告不在C ++标准之内。对包含人为错误迹象的有效程序发出警告。在您的特定情况下,您选择使用constexpr
您未定义的函数进行限定。只有在您从未调用该函数时,使用该类的程序才有效。如果确实如此,则不需要constexpr
。但是如果你打算调用那个函数(虽然忘了为它提供一个实现),但是由于一些错误(复杂的重载解析,或者只是一个愚蠢的错误),会调用另一个函数呢?
因此,Clang有责任发出警告。但是,这种情况是否值得警告是有争议的;我个人不会对GCC提出错误。
答案 1 :(得分:2)
如果您不想打电话给某个功能,那就没有必要标记它constexpr
。
constexpr
对于类型系统是不可见的(除了前C ++ 14它具有创建非静态成员函数const
的副作用);相反,它是一个承诺,对于模板类型参数和函数参数(和对象状态,对于非静态成员函数)的至少一个组合,函数的主体可以评估作为常量表达式(或等效于常量表达式的算法)。相反,函数缺少constexpr
是指令编译器甚至不尝试将函数体作为常量表达式进行求值。
Clang完全不是正确的,但它不是不正确的,因为你特别要求它拒绝有效的程序({{1} }})。您应该将警告错误视为一个强烈提示,-Werror
没有定义的函数是个坏主意。