[cfe-dev] Template programming: std::function<> vs lambda not compiling on Clang but GCC.

Christoph Siedentop via cfe-dev cfe-dev at lists.llvm.org
Thu Jan 4 09:18:35 PST 2018


Dear Clang-Mailinglist,

I found some code which does compile on GCC (7.2) but fails to compile on
Clang. Could you enlighten me, whether it should compile or not? It is
using `if constexpr` to type match a template.

* Clang complains:  "function: '...' with deduced return type cannot be
used before it is defined."
* GCC compiles this fine and main returns "6" as expected.
* I am using Clang from trunk.

Is Clang right in rejecting this code, or is GCC too permissive in
accepting this? Could you let me know, why this is the case?

Here is a minimal example, and the complete compile output for Clang. I
also tried to reduce the example further with C-Reduce, but don't think the
result aids understanding.

// Compile with -std=c++17
#include <functional>

template <typename F> decltype(auto) call(F &&f) {

  // Match F to either f(), f(int) or f(int, int).
  // Return            int, int(), or int(int, int)
  if constexpr (std::is_invocable<F>::value) {
    return f();
  } else if constexpr (std::is_invocable<F, int>::value) {
    auto b = [f]() { return f(3); };
    return call(b);
  } else {
    // Note: Error in next line.
    // If beginning replaced to read auto b = ..., it compiles on Clang.
    std::function<int(int)> b = [f](int x) { return f(x, 2); };
    return call(b);
  }
}

int main() {
  return call([](int x, int y) { return x * y; });
}

Output:
bug5_manual.cc:17:12: error: function 'call<std::__1::function<int (int)>
&>' with deduced return type cannot be used before it is defined
    return call(b);
           ^
bug5_manual.cc:4:38: note: 'call<std::__1::function<int (int)> &>' declared
here
template <typename F> decltype(auto) call(F &&f) {
                                     ^
bug5_manual.cc:22:10: error: cannot initialize return object of type 'int'
with an rvalue of type 'void'
  return call([](int x, int y) { return x * y; });
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 errors generated.

Kind regards,
Christoph


-------------------------------------

PS: Here's the reduced code. As I said, I don't think it helps much.
template <typename c, c d> struct e { static constexpr c f = d; };
typedef e<bool, true> g;
struct h : g {};
template <typename> struct i : h {};
template <typename> class function;
template <typename j, typename... k> class function<j(k...)> {};
template <typename a> auto call(a) {
  if constexpr (i<int>::f)
    ;
  else {
    function<int()> b;
    call(b);
  }
}
main() {}

Reduced with the following script. For the reduction, I got the
pre-processed code from GCC, the pre-processed code from Clang couldn't be
compiled with GCC.
#!/bin/bash
set -e

# Should continue to compile on GCC.
g++ -std=c++17 bug5.cc # NOTE: take care to use GCC 7.2 here.

clang++ -std=c++17 --compile bug5.cc 2>&1 \
| grep -q "with deduced return type cannot be used before it is defined"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180104/7883d6a5/attachment.html>


More information about the cfe-dev mailing list