Jon*_*Mee 4 c++ alias templates enable-if c++17
我问了一个有几个代码引用的问题:
template <typename...>
using void_t = void;
Run Code Online (Sandbox Code Playgroud)
我相信我有一个误解别名模板:
为什么不评估您在enable_if_tor conditional_t语句中传递给别名模板的模板参数?
以上代码是否只是一次enable_if_t执行多个模板参数?
其次,我认为我对这个角色有一个特定的误解void_t.该评论指出C++ 17标准定义void_t.这是我没有得到的:
不void_t只是一个任意的名字?如果我还要定义template <typename...> using void_t = void;我计划使用void_t的任何地方,那么标准化任意名称的重点是什么?
在Barry的例子中,来自您的链接问题:
template<typename T, typename = void>
struct has_to_string
: std::false_type { };
template<typename T>
struct has_to_string<T,
void_t<decltype(std::to_string(std::declval<T>()))>
>
: std::true_type { };
Run Code Online (Sandbox Code Playgroud)
void_t仅用于转换推导出的类型decltype,void以便它将默认参数与主模板定义匹配.SFINAE完全由decltype表达式处理.您可以轻松地执行以下操作:
//use , void() instead of wrapping in void_t
//this uses the comma operator to check the type of the to_string call, then change the type to void
decltype(std::to_string(std::declval<T>()), void())
Run Code Online (Sandbox Code Playgroud)
以前的版本更容易阅读,void_t不需要decltype工作.
如果void_t在您的实现中可用,则无需重新定义它.当它标准化时,它将像标准中的任何其他别名模板一样可用.
以这种方式思考:如果T是int,具有有效的std::to_string重载,则演绎将如下所示:
has_to_string<int>- > has_to_string<int,void>因为默认参数.所以让我们来寻找has_to_string那些参数的特化.
template<typename T>
struct has_to_string<T,
void_t<decltype(std::to_string(std::declval<T>()))>
>
: std::true_type { };
Run Code Online (Sandbox Code Playgroud)
好的,这是某些T和某些依赖类型的部分特化.让我们找出那种类型:
void_t<decltype(std::to_string(std::declval<T>()))>
//std::to_string(int&&) is valid and returns a std::string
void_t<std::string>
//void_t changes types to void
void
Run Code Online (Sandbox Code Playgroud)
现在我们的专业化看起来像这样:
template<>
struct has_to_string<int,void>
: std::true_type { };
Run Code Online (Sandbox Code Playgroud)
这符合我们的实例化has_string<int,void>,所以has_to_string<int>继承自std::true_type.
现在想来当T是struct Foo{};.再次,让我们计算出依赖类型:
void_t<decltype(std::to_string(std::declval<T>()))>
//wait, std::to_string(Foo&&) doesn't exist
//discard that specialization
Run Code Online (Sandbox Code Playgroud)
丢弃该专业化后,我们回到主要模板:
template<typename T, typename = void>
struct has_to_string
: std::false_type { };
Run Code Online (Sandbox Code Playgroud)
所以has_to_string<Foo>继承自std::false_type.
我认为所显示的示例并没有真正显示出什么void_t是好的,因为它只显示了一个用例,但是当您查看
template<typename T>
struct has_to_string<T,
void_t<decltype(std::to_string(std::declval<T>()))>
>
: std::true_type { };
Run Code Online (Sandbox Code Playgroud)
它与
template<typename T>
struct has_to_string<T,
decltype(std::to_string(std::declval<T>()), void())
>
: std::true_type { };
Run Code Online (Sandbox Code Playgroud)
对于这个声明:
前一个版本更容易阅读并且
void_t不需要decltype工作。
我认为可读性方面的优势很小,第二部分毫无意义,当decltype不起作用时,SFINAE 就会按预期启动。
void_t提案中的一个更有用的例子是:
// primary template handles types that have no nested ::type member
template< class, class = void_t<> >
struct has_type_member
: std::false_type { };
// specialization recognizes types that do have a nested ::type member
template< class T >
struct has_type_member<T, void_t<typename T::type>>
: std::true_type { }
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,即使是主模板也用来void_t增加可读性,因为它现在与专业化相匹配。这并不是绝对必要的,但我喜欢它。当你考虑其他选择时,真正的力量就会出现。如果没有void_t,专业化现在会更加复杂:
template< class T >
struct has_type_member<T, decltype(typename T::type, void())>
: std::true_type { }
Run Code Online (Sandbox Code Playgroud)
不能用作T::type类型名称,而不是表达式。因此你需要
template< class T >
struct has_type_member<T, decltype(std::declval<typename T::type>(), void())>
: std::true_type { }
Run Code Online (Sandbox Code Playgroud)
整个表达式变得更长、更棘手,并且可能会遇到您忘记处理的边缘情况。这才是void_t真正有帮助的地方,其他用途只是一个小小的改进,它们可以提高一致性。
| 归档时间: |
|
| 查看次数: |
273 次 |
| 最近记录: |