void_t在Visual Studio 2015上失败

时间:2015-08-09 19:10:16

标签: c++ visual-studio-2015 c++14 sfinae

我不明白为什么以下测试总是因Visual Studio 2015而失败(static_assert触发器):

#include <type_traits>
using namespace std;

template<class T> using try_assign = decltype(declval<T&>() = declval<T const&>());
template<class, class = void> struct my_is_copy_assignable : false_type {};
template<class T> struct my_is_copy_assignable<T, void_t<try_assign<T>>> : true_type {};

int main()
{
    static_assert(my_is_copy_assignable<int>::value, "fail");
    return 0;
}

这基本上是Walter E Brown在他的cppcon 2014演讲“现代模板元编程 - 概要”中对void_t的使用示例的转录。

重要的是要注意这个替代版本的作用,所以我认为问题不在于MSVC对表达SFINAE的不完全支持。

template<class T>
using try_assign = decltype(declval<T&>() = declval<T const&>());

template<class T>
struct my_is_copy_assignable
{
  template<class Q, class = try_assign<Q>>
  static true_type tester(Q&&);
  static false_type tester(...);
  using type = decltype(tester(declval<T>()));
};

我知道std::is_copy_assignable但我只是想更好地理解C ++不同版本中可用的各种元编程技术。我在网上看了几篇关于void_t的帖子,但我仍然不明白为什么这个例子失败了。

有趣的是,使用GCC 4.8.2它可以正常工作(使用CWG 1558解决方法,这与微软的版本相同)。

它是一个已知的Visual Studio错误,还是我做错了什么?

2 个答案:

答案 0 :(得分:4)

2014年CppCon上的Walter E. Brown也提到了以下分解,允许用任意条件替换try_assign

#include <type_traits>
#include <utility>

template<class T>
using try_assign = decltype(std::declval<T&>() = std::declval <T const &>());

template<class T, template<class> class Op, class = void>
struct is_valid : std::false_type { };

template<class T, template<class> class Op>
struct is_valid<T, Op, std::void_t<Op<T>>> : std::true_type { };

template<class T>
using is_copy_assignable = is_valid<T, try_assign>;

int main()
{
    static_assert(is_copy_assignable<int>::value, "fail");
    return 0;
}

此分解与VS 2015编译正常。现在删除is_copy_assignable并替换为is_valid。您最终会得到您提供的代码以及无法编译的代码(VS 2015)。

这表明VS 2015中存在一个错误,它与CWG 1558无关。在CWG问题中,标准不清楚别名模板特化中未使用的参数是否会导致替换失败或被忽略。

答案 1 :(得分:3)

这看起来像VC ++中的SFINAE问题。尚不支持在类模板的部分特化的模板参数中使用从属decltype。它应该在VS 2015 Update 1中有效。