我可以在所有 MSVC >= 2013 上安全地使用哪些 SFINAE 技巧?
Posted
技术标签:
【中文标题】我可以在所有 MSVC >= 2013 上安全地使用哪些 SFINAE 技巧?【英文标题】:What SFINAE tricks can I safely use on all MSVC >= 2013? 【发布时间】:2016-11-08 17:55:06 【问题描述】:在 Qt 中,我有一个绝妙的想法(咳嗽,咳嗽),开始为标准库数据类型定义 qHash
(用于 QHash 的散列函数,Qt 的关联容器之一)的重载:std::basic_string
、std::shared_ptr
和类似。
这个过程可能有一个捷径:不是追逐“任何可以用作 QHash 中的键的标准库类型”并为其添加 qHash
重载,我可以自动定义 qHash
,如果type 有一个 std::hash
专门化它(合理地假设我们不想做比标准库在这个过程中所做的更多的事情)。
也就是说,我可以使用表达式 SFINAE 来实现类似的东西:
template<typename T>
auto qHash(const T &t) -> decltype(std::hash<T>()(t))
return std::hash<T>()(t);
不幸的是,尽管 Qt 需要 C++11 编译器,但表达式 SFINAE 不允许在任何地方因为 MSVC 不完全支持它(在撰写本文时:所有 MSVC 版本,最高和包括VS15 preview 5。反正Qt必须支持到2013年)。
因此,问题是:有没有办法做同样的事情,以某种方式
-
不使用表达式 SFINAE
保证适用于所有 MSVC 版本 >= 2013?
我在想通过enable_if
之类的简单的 C++98 SFINAE 构造,但其他 SO 答案(如this one)让我认为 MSVC 2013 也可能错误编译,所以结果变成再次无法接受。
【问题讨论】:
blogs.msdn.microsoft.com/vcblog/2015/12/02/… 尝试标签调度。让您的qHash
标签调度“我可以std::hash<T>
”到使用std::hash
或不使用std::hash
的实现。对您要测试的每一件事重复此操作。
我认为您可以在std::hash::result_type
上进行 SFINAE,根据定义,std::hash
的标准提供的专业化始终是std::size_t
。即使使用原始编译器也应该可以工作。
blogs.msdn.microsoft.com/vcblog/2016/06/07/…
@HansPassant:那是关于 MSVC 2015,而不是 2013。他们都没有声称支持 SFINAE 表达式,所以我们不能使用它。 :(
【参考方案1】:
我认为您不需要为此使用 SFINAE 表达式,按照这些思路应该可以工作。
template<typename T>
typename std::hash<T>::result_type qHash(const T &t)
return std::hash<T>()(t);
或者几乎任何在hash::result_type
上执行 SFINAE 的方法。不幸的是,hash::result_type
在 C++17 中已弃用,但您仍然可以在 MSVC 2013 中使用 #ifdef
此代码。
【讨论】:
哈,当然,我正在阅读 N4594 并且发现 no 提到了std::hash<T>::result_type
...
@peppe Ta-Daa,我想你已经找到答案了 :)以上是关于我可以在所有 MSVC >= 2013 上安全地使用哪些 SFINAE 技巧?的主要内容,如果未能解决你的问题,请参考以下文章
带有 Qt 5 和 Qt Creator 的 msvc2013
LNK2001 在 VS 2013 (MSVC 18) 上,但不在 VS 2015 (MSVC 19) 上
MSVC++ 2013 似乎允许对临时对象进行赋值,有效地将它们视为左值