Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic lambda cannot be used within a namespace?

Consider the following piece of code

#include <iostream>
#include <functional>

namespace A {
    template<typename T>
    struct X {
        using Function = std::function<int(T)>;
        static Function f;
    };

    template<typename T>
    typename X<T>::Function X<T>::f = [](auto) { return 42; };

}

int main() {
    std::cout << A::X<int>::f(0);
}

Both GCC and clang accept this code but MSVC (tested version 19.00.23506) gives:

error C2888: 'auto <lambda_ce48e25aa4b9e3d225584044e4eae9e2>::operator ()(_T1) const': symbol cannot be defined within namespace 'A'

And indeed, if I remove namespace A and define everything in the global namespace, the code is accepted. Same if I make lambda expression non-generic.

Can someone explain what is the problem that MSVC sees in this code? Does C++ Standard restrict usage of generic lambdas in contexts like above?

like image 220
rafalc Avatar asked Jan 31 '18 19:01

rafalc


People also ask

What is generic lambda in C++?

Generic lambdas were introduced in C++14 . Simply, the closure type defined by the lambda expression will have a templated call operator rather than the regular, non-template call operator of C++11 's lambdas (of course, when auto appears at least once in the parameter list).

Can std :: function store Lambda?

Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.


1 Answers

Yes, this is a MSVC bug but it has been fixed on VS2017 15.6 preview 2.0

There is no specification in the standard that restricts generic lambdas to exist only in the global namespace.

POC of the problem can be found here: https://godbolt.org/g/BESMK4

MSVC is not able to deduce that auto is exactly T in every case, and fails.

In case you need to make it work with MSVC, replace auto with explicit T:

template<typename T>
typename X<T>::Function X<T>::f = [](T) { return 42; };

https://godbolt.org/g/cYG9GC

like image 128
Ivan Sanz Carasa Avatar answered Oct 05 '22 12:10

Ivan Sanz Carasa