我经常使用一种我称之为“懒人的 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
已被定义:
Error error C2995: 'unknown-type foo(F &&)': function template has already been defined c++-scratch main.cpp 15
所以我的问题是:“懒人的 enable_if
”是合法的 C++ 还是 MSVC 错误?
最佳答案
[temp.over.link]/6指定两个函数模板声明何时为重载。这是通过定义两个函数模板的等效性来完成的,如下所示:
Two function templates are equivalent if they [..] have return types [..] that are equivalent using the rules described above to compare expressions involving template parameters.
“上述规则”是
Two expressions involving template parameters are considered equivalent if two function definitions containing the expressions would satisfy the one definition rule (3.2) [..]
[basic.def.odr]/6 中说明了与这部分相关的 ODR那个
Given such an entity named
D
defined in more than one translation unit, then
- each definition of
D
shall consist of the same sequence of tokens;
显然,由于返回类型(根据 [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++ compiles it fine . 我缩短了 [temp.over.link]/6 中的引用,其中包括:
Two function templates are equivalent if they are declared in the same scope, have the same name, have identical template parameter lists [..]
其实,为了能够轻松引入新的重载,你可以使用一个小助手:
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())
Demo .
关于c++ - "lazy man' s enable_if"是合法的 C++ 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28203981/