[英]Is SFINAE forbidden in template arguments, or did I hit a clang bug?
What follows is a simplified version of a problem I hit with real code. 以下是我用实际代码命中的问题的简化版本。
Short version : just look at the code and error at gcc.godbolt.org / long version: read on ;) 简短版本 :只需查看gcc.godbolt.org / long版本中的代码和错误:继续阅读;)
Suppose I want a class with a template parameter setting
and a method int func(int)
such as: 假设我想要一个带有模板参数
setting
的类和一个方法int func(int)
例如:
setting
is false
, func
returns its argument setting
为false
, func
返回其参数 setting
is true
, func
doubles its argument setting
为true
, func
其参数加倍 The simplest way to do that is to specialize the class template: 最简单的方法是专门化类模板:
template<bool setting> struct A {
int func(x) const { return 2 * x; }
};
template<> struct A<false> {
int func(x) { return x; }
};
The problem with this approach is that if I have a bunch of other methods that don't depend on setting
, I'll have to copy-paste them in both specialization (or inherit from a common base, when there's not too much inter-dependencies). 这种方法的问题在于,如果我有一堆不依赖于
setting
的其他方法,我将不得不将它们复制粘贴到两个特化中(或者从一个公共基础继承,当没有太多的依赖)。
So instead, I can use SFINAE to select the right method, eg with std::enable_if
. 因此,我可以使用SFINAE选择正确的方法,例如使用
std::enable_if
。 This requires the method to have a template argument, because substitution failure must invalidate just the method, not the whole class. 这要求方法具有模板参数,因为替换失败必须使方法无效,而不是整个类。 As far as I know, the failure can occur in either of:
据我所知,失败可能发生在以下任何一个:
Here's the code using the method's arguments: 这是使用方法参数的代码:
template<bool setting> struct B {
template<bool when=true>
int func(int x
, typename std::enable_if<when && setting>::type * u=0
)
{ return 2 * x; }
template<bool when=true>
int func(int x
, typename std::enable_if<when && !setting>::type * u=0
)
{ return x; }
};
And here's the version using the method's template arguments: 这是使用方法的模板参数的版本:
template<bool setting> struct C {
template<bool when=true, typename std::enable_if<
when && setting
>::type...>
int func(int x) { return 2 * x; }
template<bool when=true, typename std::enable_if<
when && !setting
>::type...>
int func(int x) { return x; }
};
I tend to prefer the last version, as it makes the method's signature more readable, but that's a matter of personal taste. 我倾向于选择最后一个版本,因为它使方法的签名更具可读性,但这是个人品味的问题。
My question concerns this last version: is it valid C++ ? 我的问题涉及到最后一个版本:它是有效的C ++吗? gcc compiles it fine, but clang does not (tested with
-std=c++11
/ c++1y
/ c++1z
with same results). gcc编译得很好,但是clang没有(用
-std=c++11
/ c++1y
/ c++1z
,结果相同)。 The class definition in itself compiles OK, but the error occurs when it's instantiated: 类定义本身编译好,但是在实例化时会发生错误:
int main() {
A<true> a;
B<true> b;
C<true> c;
return a.func(1) + b.func(2) + c.func(3);
}
compiles in gcc 5.3 but not with clang 3.7.1: 在gcc 5.3中编译但不与clang 3.7.1编译:
test.cpp:30:36: error: call to member function 'func' is ambiguous
return a.func(1) + b.func(2) + c.func(3);
~~^~~~
test.cpp:20:7: note: candidate function [with when = true, $1 = <>]
int func(int x) { return 2 * x; }
^
test.cpp:23:7: note: candidate function [with when = true, $1 = <>]
int func(int x) { return x; }
^
1 error generated.
So is this valid C++ ? 这个有效的C ++也是如此? Is it a clang bug or is gcc wrong in accepting this code ?
它是一个铿锵的bug还是gcc在接受这段代码时出错了?
Is SFINAE forbidden in template arguments
模板参数中是否禁止使用SFINAE
It is valid. 这是有效的。 You may do for example:
你可能会这样做:
template<bool setting> struct C {
template<bool when=true, typename std::enable_if<
when && setting
>::type* = nullptr>
int func(int x) { return 2 * x; }
template<bool when=true, typename std::enable_if<
when && !setting
>::type* = nullptr>
int func(int x) { return x; }
};
The problem with typename std::enable_if<when && !setting>::type...
should be related to CWG 1558 . typename std::enable_if<when && !setting>::type...
应该与CWG 1558有关 。
And so your code should be correct in C++17. 所以你的代码在C ++ 17中应该是正确的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.