17

The code in question is

#include <functional>
#include <utility>

template <typename F>
void for_each(F&&) noexcept {}

template <typename F, typename T, typename... Us>
void for_each(F&& f, T&& v, Us&&... us) {
  std::invoke(std::forward<F>(f), std::forward<T>(v));
  for_each(std::forward<F>(f), std::forward<Us>(us)...);
}

void func(void*) noexcept {}

int main() {
  for_each(func, nullptr);
}

It compiles on gcc 8, but fails on clang 6 with the following error:

/opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4198:19: error: invalid application of 'sizeof' to a function type
    static_assert(sizeof(_Tp) > 0, "Type must be complete.");
                  ^~~~~~~~~~~
/opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4203:15: note: in instantiation of template class 'std::__1::__check_complete<void (void *) noexcept>' requested here
    : private __check_complete<_Tp>
              ^
/opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4496:15: note: in instantiation of template class 'std::__1::__check_complete<void (&)(void *) noexcept>' requested here
    : private __check_complete<_Fp>
              ^
/opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4559:9: note: in instantiation of template class 'std::__1::__invokable_r<void, void (&)(void *) noexcept, nullptr_t &&>' requested here
        __invokable<_Fp, _Args...>::value,
        ^
/opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4568:14: note: in instantiation of template class 'std::__1::__invoke_of<void (&)(void *) noexcept, nullptr_t &&>' requested here
    : public __invoke_of<_Fp, _Args...>
             ^
/opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4573:22: note: in instantiation of template class 'std::__1::result_of<void (&(nullptr_t &&))(void *) noexcept>' requested here
template <class _Tp> using result_of_t = typename result_of<_Tp>::type;
                     ^
/opt/wandbox/clang-6.0.0/include/c++/v1/functional:2349:1: note: in instantiation of template type alias 'result_of_t' requested here
result_of_t<_Fn&&(_Args&&...)>
^
prog.cc:9:3: note: while substituting deduced template arguments into function template 'invoke' [with _Fn = void (&)(void *) noexcept, _Args = <nullptr_t>]
  std::invoke(std::forward<F>(f), std::forward<T>(v));
  ^
prog.cc:16:3: note: in instantiation of function template specialization 'for_each<void (&)(void *) noexcept, nullptr_t>' requested here
  for_each(func, nullptr);
  ^
1 error generated.

Remove the noexcept specifier on func()

void func(void*) /* noexcept */ {}

It then compiles. I don't get this. Is this a compiler bug?

Lingxi
  • 14,579
  • 2
  • 37
  • 93

1 Answers1

19

Well no. libc++ fails to handle noexcept marked functions. It looks like its machinery fails for some reason when the function is noexcept and it takes the wrong partial specialization (the one for objects not for functions).

As you cannot take the sizeof of a function, clang rightly complains (and gcc would too).

As a workaround, pass in a function pointer:

for_each(&func, nullptr);

I filled a bug report, which was fixed! :)

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
  • 6
    Indeed. libc++'s `` has specializations of `__check_complete` for all sorts of function types, but misses the `noexcept`. This might be worth reporting to the bug tracker... – hlt May 10 '18 at 13:13
  • @Lingxi The bug has been fixed!! Thanks Eric – Rakete1111 May 12 '18 at 15:06