Общий вид лямбда, наследования и возврата: это действующий код?

Примечание. Я открываю проблему для clang, но я хотел бы быть уверенным, что мой код также действителен.


Я пытался ответить на еще один ответ, и я обнаружил некоторые трудности при игре с лямбдами и наследованием.
Рассмотрим следующий, минимальный пример:

template<typename Func>
struct Base: Func {
    Base(Func func): Func{func} {}

    template<typename... Args>
    auto operator()(Args... args)
    -> decltype(Func::operator()(args...), void()) {
        Func::operator()(args...);
    }
};

int main() {
    auto l = [](auto &&) {};
    Base<decltype(l)> mixin{l};
    mixin(0);
}

GCC 6.1 компилирует его, clang 4.0 crashes.
Обратите внимание, что оба компилируются просто отлично, используя следующее определение:

auto l = [](int) {};

Является ли этот допустимый код, или я делаю что-то, что запрещено стандартом?


Здесь есть ссылка на проблему, которую я только что открыл.

Ответ 1

Просто, если вам нужно решение для clang - следующий код должен работать с clang

#include <utility>
#include <iostream>

template <typename F>
struct Base : F
{
  Base (F f) : F {f} {}

  template <typename... Args>
  decltype(auto) operator () (Args&&... args)
  {
    std::cout << "(";
    F::operator () (std::forward<Args> (args)...);
    std::cout << ")" << std::endl;
  }
};

int
main ()
{
  auto l = [] (auto && i) {
    std::cout << i;
  };
  Base<decltype(l)> mixin {l};
  mixin (0);
  return 0;
}