我遇到G 6.1.0(-std = c 14开关)的以下问题,我不明白为什么编译器拒绝代码.
我有一个帮助结构体is_well_formed,它检查提供的模板模板参数是否形成良好的替代另一个提供的类型:
template<template<typename> typename R,typename T,typename = void> struct is_well_formed : std::false_type {}; template<template<typename> typename R,typename T> struct is_well_formed<R,T,void_t<R<T>>> : std::true_type {};
我想检查一个类型是否可引用.所以我的想法是写下列内容:
// (#1) template<class T> using reference_t = T&; static_assert(!is_well_formed<reference_t,void>::value,"Reference to void!?");
但是我收到一个编译错误:
main.cpp: In instantiation of 'struct is_well_formed<reference_t,double>': main.cpp:62:51: required from here main.cpp:54:20: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class R,class T,class> struct is_well_formed' : std::false_type {}; ^ main.cpp:54:20: note: expected a class template,got 'reference_t' main.cpp:54:20: error: type/value mismatch at argument 1 in template parameter list for 'is_well_formed<R,<template-parameter-1-3> >::is_well_formed' main.cpp:54:20: note: expected a class template,got 'reference_t'
或者,以下工作与相同的static_assert:
// (#2) template<class T> using reference_t = void_t<T&>;
此外,以下作品,真的让我困惑:
// (#3) template<class T> using pointer_t = T*; static_assert(is_well_formed<pointer_t,"No pointer to void!?");
三个别名有什么区别?是否是void_t< T&>解决方案最优雅?还是可以修改is_well_formed的helper结构来支持第一个引用版本?
编辑:我使用MSVC“15”预览4和(#1)和(#3)工作包括断言测试代码.但是当我尝试(#2)void引用的断言不起作用,即信息在替换期间丢失,并且从不选择false_type重载.哪个编译器是对的?
is_well_formed帮助器对应于SFINAE上的Stack Overflow文档页面中的can_apply结构,我刚刚删除了参数包.完整示例代码:
#include <utility> // Only defined in std for C++17 template <class...> using void_t = void; // (#1) Compiler error during substitution in is_well_formed template<class T> using reference_t = T&; // (#2) Ok,asserts work /* template<class T> using reference_t = void_t<T&>; */ // (#3) Ok,asserts work template<class T> using pointer_t = T*; template<template<typename> typename R,typename = void> struct is_well_formed : std::false_type {}; template<template<typename> typename R,void_t<R<T>>> : std::true_type {}; int main(int,char**) { static_assert(is_well_formed<reference_t,double>::value,"No reference to double!?"); static_assert(!is_well_formed<reference_t,"Reference to void!?"); static_assert(is_well_formed<pointer_t,"No pointer to double!?"); static_assert(is_well_formed<pointer_t,"No pointer to void!?"); return 0; }
解决方法
这可能是一个编译器错误,用户
T.C.在看到这篇文章后在GCC Bugzilla
here上报告.用户
Jarod42提出
template<class T> using reference = decltype(std::declval<T&>());
作为MSVC15和GCC 6.1.0的有效替代方案.此外,他指出,MSVC仍然需要long void_t定义
template <class...> struct make_void { using type = void; }; template <typename... T> using void_t = typename make_void<T...>::type;
而不是明显的
template <class...> using void_t = void;
这妨碍了原始帖子中的选项(#2)的工作.