I’m using a simple SFINAE trick to check whether a member function exists, like so:
#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()");
(I’m aware that there’s a simpler method now, but wasn’t back when I wrote this piece of code.)
This code works on GCC. Clang however issues a warning1 (all versions up to Apple LLVM 7.3, whichever that is upstream):
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;
In other word, clang expects the functions to be defined, not just declared, even though they are never called (only in the unevaluated context of decltype
).
Is this a bug in clang? Or is it right to complain? If so, is GCC also correct in accepting this code?
Furthermore, while writing this question I realised that the clang compilation error can be avoided altogether by removing the constexpr
qualifier in front of the member function template. What does the presence of constexpr
change here?
1 Which is a problem as I’m compiling with -Werror
. There are some warnings that are based on heuristics and therefore have unavoidable false positives, but this isn’t the case here as far as I can see.
If you aren't intending ever to call a function, there's no point marking it constexpr
.
constexpr
on a function isn't visible to the type system (well, except that pre-C++14 it had the side effect of making a non-static member function const
); rather, it's a promise that for at least one combination of template type arguments and function arguments (and object state, for a non-static member function) the body of the function can be evaluated as a constant expression (or an algorithm equivalent to a constant expression). Conversely, the lack of constexpr
on a function is an instruction to the compiler not to even attempt to evaluate the function body as a constant expression.
Clang isn't correct, exactly, but it isn't incorrect, either, as you've specifically asked it to reject valid programs (with -Werror
). You should take the warning-error as a strong hint that constexpr
functions without a definition are a bad idea.
Is this a bug in clang? Or is it right to complain? If so, is GCC also correct in accepting this code?
Furthermore, while writing this question I realised that the clang compilation error can be avoided altogether by removing the
constexpr
qualifier in front of the member function template. What does the presence ofconstexpr
change here?
Compiler warnings are outside the C++ standard. Warnings are issued for valid programs that contain indications of human error. In your particular case, you chose to qualify with a constexpr
a function that you did not define. Programs using that class will be valid only if you never call that function. If that's really the case then constexpr
is not needed. But what if you intended to call that function (though forgot to provide an implementation for it), but due to some mistake (complex overload resolution, or just a stupid typo) a different function was called?
Thus Clang has its point in issuing the warning. However, it is arguable whether that situation deserves a warning; personally I wouldn't file a bug against GCC.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With