noexcept + declval 无法在 MSVC 下编译
noexcept + declval fail to compile under MSVC
我正在尝试实现我对 SO 问题 的回答:
我的目标是检测模板 class T
中是否存在 void cancel() noexcept
方法。
这是我的最小示例:
#include <iostream>
#include <type_traits>
template<class T, class = void>
struct has_cancel : std::false_type {};
template<class T>
struct has_cancel<T,
typename std::void_t<decltype(std::declval<T>().cancel()),
typename std::enable_if_t<noexcept(std::declval<T>().cancel())>
>
> : std::true_type {};
void print_has_cancel(std::true_type) {
std::cout << "cancel found" << std::endl;
}
void print_has_cancel(std::false_type) {
std::cout << "cancel not found" << std::endl;
}
struct A{
};
struct B {
void cancel(){}
};
struct C {
int cancel() noexcept {}
};
struct D{
void cancel() noexcept {}
};
int main(){
print_has_cancel(has_cancel<A>());
print_has_cancel(has_cancel<B>());
print_has_cancel(has_cancel<C>());
print_has_cancel(has_cancel<D>());
return 0;
}
Visual studio 社区 2019 年的输出:
1>------ Build started: Project: cpp_sandbox, Configuration: Debug x64 ------
1>cpp_sandbox.cpp
1>C:\Users\David Haim\source\repos\cpp_sandbox\cpp_sandbox\cpp_sandbox.cpp(10,1): error C2228: left of '.cancel' must have class/struct/union
1>C:\Users\David Haim\source\repos\cpp_sandbox\cpp_sandbox\cpp_sandbox.cpp(10,1): message : type is '_Add_reference<_Ty,void>::_Rvalue'
1>C:\Users\David Haim\source\repos\cpp_sandbox\cpp_sandbox\cpp_sandbox.cpp(10,19): error C2056: illegal expression
1>Done building project "cpp_sandbox.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
经过一些研究,问题出在语法上 noexcept(std::declval<type>().something())
- MSVC 拒绝理解这一行。
1) 为什么 MSVC 抱怨?错误是在代码中还是在编译器中?
2) 我怎样才能编译它?
MSVC 的语法本身没有问题。它似乎只是假设 SFINAE 在这种情况下不适用,因此将 void
替换为类型会给出错误。为什么或是否在标准中对此有任何支持,我目前不知道(但我怀疑)。
这可以通过将声明中的 noexcept
条件移动到 struct
的定义中来轻松解决,这样如果第一个 decltype
有问题,它就永远不会被替换-形成(即如果 .cancel()
根本不存在)并且 SFINAE 开始:
template<class T>
struct has_cancel<T,
typename std::void_t<decltype(std::declval<T>().cancel()) >
> : std::bool_constant<noexcept(std::declval<T>().cancel())> {};
我正在尝试实现我对 SO 问题 T
中是否存在 void cancel() noexcept
方法。
这是我的最小示例:
#include <iostream>
#include <type_traits>
template<class T, class = void>
struct has_cancel : std::false_type {};
template<class T>
struct has_cancel<T,
typename std::void_t<decltype(std::declval<T>().cancel()),
typename std::enable_if_t<noexcept(std::declval<T>().cancel())>
>
> : std::true_type {};
void print_has_cancel(std::true_type) {
std::cout << "cancel found" << std::endl;
}
void print_has_cancel(std::false_type) {
std::cout << "cancel not found" << std::endl;
}
struct A{
};
struct B {
void cancel(){}
};
struct C {
int cancel() noexcept {}
};
struct D{
void cancel() noexcept {}
};
int main(){
print_has_cancel(has_cancel<A>());
print_has_cancel(has_cancel<B>());
print_has_cancel(has_cancel<C>());
print_has_cancel(has_cancel<D>());
return 0;
}
Visual studio 社区 2019 年的输出:
1>------ Build started: Project: cpp_sandbox, Configuration: Debug x64 ------
1>cpp_sandbox.cpp
1>C:\Users\David Haim\source\repos\cpp_sandbox\cpp_sandbox\cpp_sandbox.cpp(10,1): error C2228: left of '.cancel' must have class/struct/union
1>C:\Users\David Haim\source\repos\cpp_sandbox\cpp_sandbox\cpp_sandbox.cpp(10,1): message : type is '_Add_reference<_Ty,void>::_Rvalue'
1>C:\Users\David Haim\source\repos\cpp_sandbox\cpp_sandbox\cpp_sandbox.cpp(10,19): error C2056: illegal expression
1>Done building project "cpp_sandbox.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
经过一些研究,问题出在语法上 noexcept(std::declval<type>().something())
- MSVC 拒绝理解这一行。
1) 为什么 MSVC 抱怨?错误是在代码中还是在编译器中?
2) 我怎样才能编译它?
MSVC 的语法本身没有问题。它似乎只是假设 SFINAE 在这种情况下不适用,因此将 void
替换为类型会给出错误。为什么或是否在标准中对此有任何支持,我目前不知道(但我怀疑)。
这可以通过将声明中的 noexcept
条件移动到 struct
的定义中来轻松解决,这样如果第一个 decltype
有问题,它就永远不会被替换-形成(即如果 .cancel()
根本不存在)并且 SFINAE 开始:
template<class T>
struct has_cancel<T,
typename std::void_t<decltype(std::declval<T>().cancel()) >
> : std::bool_constant<noexcept(std::declval<T>().cancel())> {};