Konrad Rudolph Konrad Rudolph - 1 year ago 149
C++ Question

Clang complains about undefined constexpr function in unevaluated context

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

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
qualifier in front of the member function template. What does the presence of
change here?

1 Which is a problem as I’m compiling with
. 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.

Answer Source

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.