"lazy man's enable_if"合法C++吗?
Is the "lazy man's enable_if" legal C++?
我经常使用一种我称之为"懒人enable_if
"的技术,我使用decltype
和逗号运算符来启用基于某些模板输入的功能。这里有一个小例子:
template <typename F>
auto foo(F&& f) -> decltype(f(0), void())
{
std::cout << "1" << std::endl;
}
template <typename F>
auto foo(F&& f) -> decltype(f(0, 1), void())
{
std::cout << "2" << std::endl;
}
使用 --std=c++11
、g++ 4.7+ 和 Clang 3.5+ 愉快地编译了这段代码(它的工作方式符合我的预期)。但是,在使用 MSVC 14 CTP5 时,我收到此错误,抱怨已经定义了foo
:
错误错误 C2995:"未知类型 foo(F &&)":函数模板具有 已经定义了 C++-Scratch main.cpp 15
所以我的问题是:"懒人的enable_if
"是合法的C++还是MSVC错误?
[temp.over.link]/6 指定两个函数模板声明何时是重载。这是通过定义两个函数模板的等效性来完成的,如下所示:
如果两个函数模板的 [..] 具有使用规则等效的返回类型 [..] ,则它们是等效的 用于比较涉及模板参数的表达式。
上述"规则"是
考虑两个涉及模板参数的表达式 等效的,如果包含表达式的两个函数定义满足一个定义规则 (3.2) [..]
与本部分相关的 ODR 在 [basic.def.odr]/6 中指出
显然,由于返回类型给定这样一个在多个翻译中定义
D
实体 单位,然后
D
的每个定义应由相同的令牌序列组成;
(根据 [dcl.fct]/2 是尾随返回类型)不包含相同的标记,因此包含这些表达式的两个函数定义将违反 ODR。
因此,foo
声明非等效的函数模板并重载名称。
您看到的错误是由于 VC++ 缺乏对表达式 SFINAE 的支持而发出的 - 大概没有检查尾随返回类型是否等效。
解决方法
您可以通过其他方式使函数模板不等效 - 更改模板参数列表。如果像这样重写第二个定义:
template <typename F, int=0>
auto foo(F&& f) -> decltype(f(0, 1), void())
{
std::cout << "2" << std::endl;
}
然后VC++编译得很好。我缩短了 [temp.over.link]/6 中的引文,其中涵盖了以下内容:
如果两个函数模板在同一函数模板中声明,则它们是等效的 范围,具有相同的名称,具有相同的模板参数列表 [..]
实际上,为了能够轻松引入新的重载,您可以使用一个小助手:
template <int I>
using overload = std::integral_constant<int, I>*;
用法是例如
// Remember to separate > and = with whitespace
template <typename... F, overload<0> = nullptr>
auto foo(F&&... f) -> decltype(f(0, 1)..., void())
template <typename... F, overload<1> = nullptr>
auto foo(F&&... f) -> decltype(f(0, 1, 2)..., void())
演示。
这是一个称为"表达SFINAE"的功能。 Visual C++ 尚不完全支持此功能(请参阅"VS 2015 预览版中的 C++11/14/17 功能",了解截至本回答时的最新一致性更新)。
- 我的简单if-else语句是如何无法访问的代码
- 如何将enable-if与模板参数和参数包一起使用
- 无论条件是否为true,if总是在c++中执行
- Arduino:for/while/if在void setup()或void loop()之前?——错误:之前需要不合格
- Insert函数不适用于2 if语句C++
- If语句未被求值C++
- C++嵌套if语句,基本货币交换
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 是否可以使用if constexpr删除控制流语句
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 如何删除peer if else分支中的冗长句子
- 我似乎对if/else的基本语句有问题:/
- if数组上的随机数
- 将按位if条件转换为普通if条件
- If语句在c++中被忽略
- 比较if语句中的数组值和int值
- std::vector::迭代器是否可以合法地作为指针
- 使用if-else将数字转换为单词
- 为什么简单的算术减法在"if"条件下不起作用?
- 以在Qt中的IF语句中设置时间延迟