我需要一个简单的类型特征来检测事物是否是无法自动交换的。标准库中没有,所以我写了这个。它适用于gcc和clang,至少我几个月没有问题地使用它。
今天我也尝试使用MSVC 2015编译,它提供了一个非常简洁的编译错误,我想了解。
这是一个MVCE:
#include <utility>
#include <type_traits>
// Code is targetting C++11 so we have to backport this:
template <bool b, typename V = void>
using enable_if_t = typename std::enable_if<b, V>::type;
namespace detail {
using std::swap;
// Need to use SFINAE for this in case there is no `swap`.
template <typename T, typename ENABLE = void>
struct is_nothrow_swappable : std::false_type {};
template <typename T>
struct is_nothrow_swappable<T, enable_if_t<noexcept(
swap(*static_cast<T *>(nullptr),
*static_cast<T *>(nullptr)))>>
: std::true_type {};
} // end namespace detail
// Tests
static_assert(detail::is_nothrow_swappable<int>::value, "");
static_assert(detail::is_nothrow_swappable<std::pair<int, int>>::value, "");
struct B {};
static_assert(detail::is_nothrow_swappable<B>::value, "");
struct A {
A() = delete;
A(A&&) = delete;
};
static_assert(!detail::is_nothrow_swappable<A>::value, "");
int main() {}
开rextester.com我重现上述错误:
Error(s):
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\utility(49): error C2057: expected constant expression
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\utility(48): note: see reference to function template instantiation 'void std::swap<T>(_Ty &,_Ty &) noexcept(<expr>)' being compiled
source_file.cpp(6): error C2039: 'type': is not a member of 'std::enable_if<false,V>'
with
[
V=void
]
source_file.cpp(18): error C2061: syntax error: identifier 'type'
source_file.cpp(18): error C2938: 'enable_if_t<false,void>' : Failed to specialize alias template
source_file.cpp(18): error C2059: syntax error: '<end Parse>'
source_file.cpp(24): error C2338:
source_file.cpp(25): error C2338:
source_file.cpp(29): error C2338:
好吧,MSVC说这不是一个持续的表达,而是究竟是什么以及为什么?
这基本上是msvc constexpr
支持的错误吗?
或者,这是“表达SFINAE”的意思,错误是因为msvc不支持它?如果是这样我可以解决它吗?
这实际上不是有效的C ++ 11代码,它恰好被gcc和clang接受了吗?
浏览后,我找到了std::is_nothrow_swappable
的工作组提案,其附录和示例代码与我的有所不同:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0185r1.html#Appendix
此实现在所有计算机上编译:
struct do_is_nothrow_swappable
{
template<class T>
static auto test(int) -> std::integral_constant<bool,
noexcept(swap(std::declval<T&>(), std::declval<T&>()))
>;
template<class>
static std::false_type test(...);
};
template <typename T>
struct is_nothrow_swappable : decltype(
do_is_nothrow_swappable::test<T>(0)
)
{};
所以我的问题得到了有效解决,但问题是,为什么实际上一个工作而另一个工作失败?我的尝试究竟出了什么问题?如果你能解释我会非常感激。