为什么模板参数中的 enable_if_t 会抱怨重新定义?
我有以下情况可以使用 std::enable_if
:
template::value>::type* = nullptr>无效 f() { }模板<类型名 T,typename std::enable_if::value>::type* = nullptr>无效 f() { }
现在,我在 cppreference 中看到了新语法,在我看来更清晰:typename = std::enable_if_t<std::is_same<int, T>::value>>
>
我想移植我的代码:
template::value>>无效 g() { }模板<类型名 T,typename = std::enable_if_t::value>>无效 g() { }
但现在 GCC (5.2) 抱怨:
error: redefinition of 'template空 g()'无效 g() { }
为什么会这样?如果可能的话,在这种情况下我该怎么做才能拥有新的、更简洁的语法?
解决方案让我们删除一些代码.
模板::value>*/>无效 g() { }模板::value>*/>无效 g() { }
如果编译器拒绝了上述两个模板,您会感到惊讶吗?
它们都是类型"的模板函数template
.第二种类型参数具有不同的默认值这一事实无关紧要.这就像期望两个不同的 print(string, int)
函数具有不同的默认 int
值来重载.;)
在第一种情况下,我们有:
模板<类型名称 T,typename std::enable_if::value>::type* = nullptr>无效 f() { }模板<类型名称 T,typename std::enable_if::value>::type* = nullptr>无效 f() { }
这里我们不能删除 enable_if
子句.更新到 enable_if_t
:
模板::value, int>* = nullptr>无效 f() { }模板::value, int>* = nullptr>无效 f() { }
我还用 class
替换了 typename
的使用.我怀疑你的困惑是因为 typename
有两个含义――一个作为一种 template
参数的标记,另一个作为依赖类型的消歧义.
这里的第二个参数是一个指针,它的类型依赖于第一个.编译器无法在不首先替换类型 T
的情况下确定这两者是否冲突――并且您会注意到它们实际上永远不会发生冲突.
I have the following case that works using std::enable_if
:
template<typename T,
typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr>
void f() { }
template<typename T,
typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr>
void f() { }
Now, I saw in cppreference the new syntax, much cleaner in my opinion : typename = std::enable_if_t<std::is_same<int, T>::value>>
I wanted to port my code :
template<typename T,
typename = std::enable_if_t<std::is_same<int, T>::value>>
void g() { }
template<typename T,
typename = std::enable_if_t<std::is_same<double, T>::value>>
void g() { }
But now GCC (5.2) complains :
error: redefinition of 'template<class T, class> void g()'
void g() { }
Why is that so ? What can I do to have the new, more concise syntax in this case if this is possible ?
解决方案Let's remove some code.
template<
class T,
class U/* = std::enable_if_t<std::is_same<int, T>::value>*/
>
void g() { }
template<
class T,
class U/* = std::enable_if_t<std::is_same<double, T>::value>*/
>
void g() { }
would you be surprised if the compiler rejected the two above templates?
They are both template functions of "type" template<class,class>void()
. The fact that the 2nd type argument has a different default value matters not. That would be like expecting two different print(string, int)
functions with different default int
values to overload. ;)
In the first case we have:
template<
typename T,
typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr
>
void f() { }
template<
typename T,
typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr
>
void f() { }
here we cannot remove the enable_if
clause. Updating to enable_if_t
:
template<
class T,
std::enable_if_t<std::is_same<int, T>::value, int>* = nullptr
>
void f() { }
template<
class T,
std::enable_if_t<std::is_same<double, T>::value, int>* = nullptr
>
void f() { }
I also replaced a use of typename
with class
. I suspect your confusion was because typename
has two meanings -- one as a marker for a kind of template
argument, and another as a disambiguator for a dependent type.
Here the 2nd argument is a pointer, whose type is dependent on the first. The compiler cannot determine if these two conflict without first substituting in the type T
-- and you'll note that they will never actually conflict.
相关文章