如何检测通用 lambda 在 C++ 14 中是否不可编译?
How to detect if a generic lambda is uncompilable in C++ 14?
我在检测通用 lambda 的实例何时格式正确但不可编译时遇到问题,检测它让我很困惑:
#include <functional>
class future
{
public:
int get() & { return 5; }
};
// Gets the return type of F(A), returning a not_well_formed type if not well formed
template<class F, class A> struct get_return_type
{
struct not_well_formed {};
template<class _F, class _A> static not_well_formed test(...);
template<class _F, class _A> static auto test(_F &&f) noexcept(noexcept(f(std::declval<_A>()))) -> decltype(f(std::declval<_A>()));
using type = decltype(test<F, A>(std::declval<F>()));
static constexpr bool is_noexcept = noexcept(test<F, A>(std::declval<F>()));
};
int main(void)
{
auto foo=[](auto &&x) { return x.get(); };
using type=get_return_type<decltype(foo), const future>::type;
return 0;
}
这失败了(在 clang 3.7 上):
ned@kate:~$ clang++-3.7 -std=c++14 -o weird_generic_lambda_thing weird_generic_lambda_thing.cpp
weird_generic_lambda_thing.cpp:21:34: error: member function 'get' not viable: 'this' argument has type 'const future', but
function is not marked const
auto foo=[](auto &&x) { return x.get(); };
^
weird_generic_lambda_thing.cpp:14:111: note: in instantiation of function template specialization 'main()::(anonymous
class)::operator()<const future>' requested here
..._F, class _A> static auto test(_F &&f) noexcept(noexcept(f(std::declval<_A>()))) -> decltype(f(std::declval<_A>()));
^
weird_generic_lambda_thing.cpp:15:25: note: while substituting explicitly-specified template arguments into function
template 'test'
using type = decltype(test<F, A>(std::declval<F>()));
^
weird_generic_lambda_thing.cpp:22:14: note: in instantiation of template class 'get_return_type<(lambda at
weird_generic_lambda_thing.cpp:21:12), const future>' requested here
using type=get_return_type<decltype(foo), const future>::type;
^
weird_generic_lambda_thing.cpp:6:7: note: 'get' declared here
int get() & { return 5; }
^
1 error generated.
你可能会在这里责备我对 Expression SFINAE 缺乏经验(感谢 Visual Studio!),但我很惊讶:创建 return 类型的 test() 的 decltype 肯定无法替代f(std::declval<_A>())
格式不正确?
显然答案是无法替代,但以非 SFINAE 方式。如果泛型 lambda 无法使用某些任意参数类型进行编译,是否可以修复上述问题,使其正确 return 成为 not_well_formed 类型?
一般情况下不能。通过 SFINAE 只能检测到早期故障。早期的失败基本上是函数(或class)模板的声明,而不是定义。
lambda 可以通过显式声明 return 类型 ->decltype(x.get())
或通过 enable_if_t
或 void_t
等其他 SFINAE 技术提供 SFINAE 早期故障检测。
这个想法是编译器不需要完全编译函数来进行重载解析。
我在检测通用 lambda 的实例何时格式正确但不可编译时遇到问题,检测它让我很困惑:
#include <functional>
class future
{
public:
int get() & { return 5; }
};
// Gets the return type of F(A), returning a not_well_formed type if not well formed
template<class F, class A> struct get_return_type
{
struct not_well_formed {};
template<class _F, class _A> static not_well_formed test(...);
template<class _F, class _A> static auto test(_F &&f) noexcept(noexcept(f(std::declval<_A>()))) -> decltype(f(std::declval<_A>()));
using type = decltype(test<F, A>(std::declval<F>()));
static constexpr bool is_noexcept = noexcept(test<F, A>(std::declval<F>()));
};
int main(void)
{
auto foo=[](auto &&x) { return x.get(); };
using type=get_return_type<decltype(foo), const future>::type;
return 0;
}
这失败了(在 clang 3.7 上):
ned@kate:~$ clang++-3.7 -std=c++14 -o weird_generic_lambda_thing weird_generic_lambda_thing.cpp
weird_generic_lambda_thing.cpp:21:34: error: member function 'get' not viable: 'this' argument has type 'const future', but
function is not marked const
auto foo=[](auto &&x) { return x.get(); };
^
weird_generic_lambda_thing.cpp:14:111: note: in instantiation of function template specialization 'main()::(anonymous
class)::operator()<const future>' requested here
..._F, class _A> static auto test(_F &&f) noexcept(noexcept(f(std::declval<_A>()))) -> decltype(f(std::declval<_A>()));
^
weird_generic_lambda_thing.cpp:15:25: note: while substituting explicitly-specified template arguments into function
template 'test'
using type = decltype(test<F, A>(std::declval<F>()));
^
weird_generic_lambda_thing.cpp:22:14: note: in instantiation of template class 'get_return_type<(lambda at
weird_generic_lambda_thing.cpp:21:12), const future>' requested here
using type=get_return_type<decltype(foo), const future>::type;
^
weird_generic_lambda_thing.cpp:6:7: note: 'get' declared here
int get() & { return 5; }
^
1 error generated.
你可能会在这里责备我对 Expression SFINAE 缺乏经验(感谢 Visual Studio!),但我很惊讶:创建 return 类型的 test() 的 decltype 肯定无法替代f(std::declval<_A>())
格式不正确?
显然答案是无法替代,但以非 SFINAE 方式。如果泛型 lambda 无法使用某些任意参数类型进行编译,是否可以修复上述问题,使其正确 return 成为 not_well_formed 类型?
一般情况下不能。通过 SFINAE 只能检测到早期故障。早期的失败基本上是函数(或class)模板的声明,而不是定义。
lambda 可以通过显式声明 return 类型 ->decltype(x.get())
或通过 enable_if_t
或 void_t
等其他 SFINAE 技术提供 SFINAE 早期故障检测。
这个想法是编译器不需要完全编译函数来进行重载解析。