转换运算符:gcc vs clang
Conversion operator: gcc vs clang
考虑以下代码 (https://godbolt.org/z/s17aoczj6):
template<class T>
class Wrapper {
public:
explicit Wrapper(T t): _value(t) {}
template<class S = T>
operator T() { return _value; }
private:
T _value;
};
auto main() -> int
{
auto i = int{0};
auto x = Wrapper<int>(i);
return x + i;
}
它用 clang 编译,但不能用 gcc(所有版本)编译。
它在删除 template<class S = T>
时在 gcc 中工作。
此代码格式错误还是某个编译器错误?
gcc 中的错误是error: no match for 'operator+' (operand types are 'Wrapper<int>' and 'int') return x + i;
。
我想要转换为 T
。此示例中不需要模板,但在非最小示例中,我想使用 SFINAE,因此此处需要一个模板。
当你有 x + i
时,因为 x
是 class 类型,重载解析开始:
具体细节来自标准 ([over.match.oper]p2)
If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator.
In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator.
内置候选在第 3.3 段中定义:
For the operator ,
, the unary operator &
, or the operator ->
, the built-in candidates set is empty. For all other operators, the built-in candidates include all of the candidate operator functions defined in [over.built] that, compared to the given operator,
- have the same operator name, and
- accept the same number of operands, and
- accept operand types to which the given operand or operands can be converted according to [over.best.ics], and
- do not have the same parameter-type-list as any non-member candidate that is not a function template specialization.
根据 [over.built]p13,内置候选函数可能包括:
For every pair of types L and R, where each of L and R is a floating-point or promoted integral type, there exist candidate operator functions of the form
LR operator*(L, R);
...
LR operator+(L, R);
...
bool operator>=(L, R);
where LR is the result of the usual arithmetic conversions ([expr.arith.conv]) between types L and R.
所以有一个内置函数int operator+(int, int)
。
至于有哪些可能的隐式转换序列:
[over.best.ics]p3:
A well-formed implicit conversion sequence is one of the following forms:
- a standard conversion sequence,
- a user-defined conversion sequence, or
- an ellipsis conversion sequence.
这里使用了用户自定义的转换序列,定义为[over.ics.user]:
A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion ([class.conv]) followed by a second standard conversion sequence.
(这里,两个标准转换序列都是空的,可以使用你自定义的转换为int
)
因此,当检查 int operator+(int, int)
是否为内置候选时,是因为在您的 class 类型和 int
之间存在转换。
至于实际的重载解析,来自[over.match.oper]:
- The set of candidate functions for overload resolution for some operator @ is the union of the member candidates, the non-member candidates, the built-in candidates, and the rewritten candidates for that operator @.
- The argument list contains all of the operands of the operator.
The best function from the set of candidate functions is selected according to [over.match.viable] and [over.match.best].
和 int operator+(int, int)
显然是最佳匹配,因为它不需要对第二个参数进行转换,而只需要对第一个参数进行用户定义的转换,因此它击败了其他候选者,如 long operator+(long, int)
和 long operator+(int, long)
您可以看到内置候选集为空的问题,因为 GCC 错误报告有 no 个可行的候选集。如果你有:
auto add(int a, int b) -> int
{
return a + b;
}
auto main() -> int
{
auto i = int{0};
auto x = Wrapper<int>(i);
return add(x, i);
}
它现在可以很好地与 GCC 编译,因为 ::add(int, int)
被认为是一个候选者,即使它应该与内置运算符 int operator+(int, int)
.
没有什么不同
如果你有:
template<class S = T>
operator S() { return _value; } // Can convert to any type
Clang 现在出现错误:
<source>:16:14: error: use of overloaded operator '+' is ambiguous (with operand types 'Wrapper<int>' and 'int')
return x + i;
~ ^ ~
<source>:16:14: note: built-in candidate operator+(float, int)
<source>:16:14: note: built-in candidate operator+(double, int)
<source>:16:14: note: built-in candidate operator+(long double, int)
<source>:16:14: note: built-in candidate operator+(__float128, int)
<source>:16:14: note: built-in candidate operator+(int, int)
<source>:16:14: note: built-in candidate operator+(long, int)
<source>:16:14: note: built-in candidate operator+(long long, int)
<source>:16:14: note: built-in candidate operator+(__int128, int)
<source>:16:14: note: built-in candidate operator+(unsigned int, int)
<source>:16:14: note: built-in candidate operator+(unsigned long, int)
<source>:16:14: note: built-in candidate operator+(unsigned long long, int)
<source>:16:14: note: built-in candidate operator+(unsigned __int128, int)
(请注意,此错误消息不包括第二个参数的转换,但由于永远不会选择这些,因此它们可能不被视为优化)
而且 GCC 仍然说根本没有候选者,即使所有这些内置候选者都存在。
考虑以下代码 (https://godbolt.org/z/s17aoczj6):
template<class T>
class Wrapper {
public:
explicit Wrapper(T t): _value(t) {}
template<class S = T>
operator T() { return _value; }
private:
T _value;
};
auto main() -> int
{
auto i = int{0};
auto x = Wrapper<int>(i);
return x + i;
}
它用 clang 编译,但不能用 gcc(所有版本)编译。
它在删除 template<class S = T>
时在 gcc 中工作。
此代码格式错误还是某个编译器错误?
gcc 中的错误是error: no match for 'operator+' (operand types are 'Wrapper<int>' and 'int') return x + i;
。
我想要转换为 T
。此示例中不需要模板,但在非最小示例中,我想使用 SFINAE,因此此处需要一个模板。
当你有 x + i
时,因为 x
是 class 类型,重载解析开始:
具体细节来自标准 ([over.match.oper]p2)
If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator.
内置候选在第 3.3 段中定义:
For the
operator ,
, the unaryoperator &
, or theoperator ->
, the built-in candidates set is empty. For all other operators, the built-in candidates include all of the candidate operator functions defined in [over.built] that, compared to the given operator,
- have the same operator name, and
- accept the same number of operands, and
- accept operand types to which the given operand or operands can be converted according to [over.best.ics], and
- do not have the same parameter-type-list as any non-member candidate that is not a function template specialization.
根据 [over.built]p13,内置候选函数可能包括:
For every pair of types L and R, where each of L and R is a floating-point or promoted integral type, there exist candidate operator functions of the form
LR operator*(L, R); ... LR operator+(L, R); ... bool operator>=(L, R);
where LR is the result of the usual arithmetic conversions ([expr.arith.conv]) between types L and R.
所以有一个内置函数int operator+(int, int)
。
至于有哪些可能的隐式转换序列:
[over.best.ics]p3:
A well-formed implicit conversion sequence is one of the following forms:
- a standard conversion sequence,
- a user-defined conversion sequence, or
- an ellipsis conversion sequence.
这里使用了用户自定义的转换序列,定义为[over.ics.user]:
A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion ([class.conv]) followed by a second standard conversion sequence.
(这里,两个标准转换序列都是空的,可以使用你自定义的转换为int
)
因此,当检查 int operator+(int, int)
是否为内置候选时,是因为在您的 class 类型和 int
之间存在转换。
至于实际的重载解析,来自[over.match.oper]:
- The set of candidate functions for overload resolution for some operator @ is the union of the member candidates, the non-member candidates, the built-in candidates, and the rewritten candidates for that operator @.
- The argument list contains all of the operands of the operator. The best function from the set of candidate functions is selected according to [over.match.viable] and [over.match.best].
和 int operator+(int, int)
显然是最佳匹配,因为它不需要对第二个参数进行转换,而只需要对第一个参数进行用户定义的转换,因此它击败了其他候选者,如 long operator+(long, int)
和 long operator+(int, long)
您可以看到内置候选集为空的问题,因为 GCC 错误报告有 no 个可行的候选集。如果你有:
auto add(int a, int b) -> int
{
return a + b;
}
auto main() -> int
{
auto i = int{0};
auto x = Wrapper<int>(i);
return add(x, i);
}
它现在可以很好地与 GCC 编译,因为 ::add(int, int)
被认为是一个候选者,即使它应该与内置运算符 int operator+(int, int)
.
如果你有:
template<class S = T>
operator S() { return _value; } // Can convert to any type
Clang 现在出现错误:
<source>:16:14: error: use of overloaded operator '+' is ambiguous (with operand types 'Wrapper<int>' and 'int')
return x + i;
~ ^ ~
<source>:16:14: note: built-in candidate operator+(float, int)
<source>:16:14: note: built-in candidate operator+(double, int)
<source>:16:14: note: built-in candidate operator+(long double, int)
<source>:16:14: note: built-in candidate operator+(__float128, int)
<source>:16:14: note: built-in candidate operator+(int, int)
<source>:16:14: note: built-in candidate operator+(long, int)
<source>:16:14: note: built-in candidate operator+(long long, int)
<source>:16:14: note: built-in candidate operator+(__int128, int)
<source>:16:14: note: built-in candidate operator+(unsigned int, int)
<source>:16:14: note: built-in candidate operator+(unsigned long, int)
<source>:16:14: note: built-in candidate operator+(unsigned long long, int)
<source>:16:14: note: built-in candidate operator+(unsigned __int128, int)
(请注意,此错误消息不包括第二个参数的转换,但由于永远不会选择这些,因此它们可能不被视为优化)
而且 GCC 仍然说根本没有候选者,即使所有这些内置候选者都存在。