在运算符重载中使用可变参数模板是否合法?
Is it legal to use variadic templates in operator overloading?
我希望能够按照这些思路写一些东西:
struct bar {};
template <typename ... Args>
bar operator+(bar, Args ...)
{}
我刚刚检查了 clang/gcc,重载运算符被二进制表达式 (a+b
) 和一元表达式 (+a
) 拾取,如我所料。然而,运算符比普通函数更受限制,例如 - 你不能用三个参数重载 operator+()
。
以上用法是否合法且可移植?
EDIT 为了提供一些上下文,我显然不希望能够定义可变参数运算符或任何类似的东西。我对此感兴趣的原因是一个丑陋的 hack:我想让一些运算符可变,这样我就可以 "override" 它们与其他非可变实现。由于可变参数模板在函数模板重载规则中被认为不如非可变参数模板专业,因此我可以用非可变参数操作符覆盖可变参数操作符。是的,这太可怕了:)
首先,定义很好,因为存在非空包的有效特化1。
现在,特定表达式 a+b
或 +a
是 i.a。分别转换为 operator+(a, b)
和 operator+(a)
形式的非成员调用([over.match.oper]/2). Name lookup then finds the operator function template, whose specialization becomes part of the candidates. Finally, [over.match.oper]/6 只是像往常一样委托重载决策:
The set of candidate functions for overload resolution is the union of
the member candidates, the non-member candidates, and the built-in
candidates. The argument list contains all of the operands of the
operator. The best function from the set of candidate functions is
selected according to 13.3.2 and 13.3.3.
您的代码也将按预期工作,因为重载解析和部分排序将像所有其他代码一样遵守运算符函数模板。
1 为一元运算符声明以上内容,可能除了后缀 --
和 ++
之外,格式错误,不需要诊断。比照。 [temp.res]/(8.2).
标准限制 运算符函数 的参数数量(以及默认参数的存在),在 [over.oper]:
中
8 - An operator function cannot have default arguments ([dcl.fct.default]), except where explicitly stated below. Operator
functions cannot have more or fewer parameters than the number required for the corresponding operator,
as described in the rest of this subclause.
但是,您声明的是运算符函数模板,没有这样的限制。这意味着您的代码没问题;一元或二进制 +
的使用将转换为使用一个或两个参数调用 operator+
,并相应地生成模板的适当实例化。
如果您使用非法数量的参数专门化或显式实例化运算符函数模板,那将是非法的,因为 ([over.oper]):
1 - [...] A specialization of an operator function template is also an operator
function. [...]
请注意,如果我们编写一个可以用不正确类型实例化的非可变运算符函数模板,则会产生类似的效果:
template<class T> int operator+(T, T) { return 0; } // OK
struct bar {}; template int operator+(bar, bar); // OK
template int operator+(int, int); // Error is here
我希望能够按照这些思路写一些东西:
struct bar {};
template <typename ... Args>
bar operator+(bar, Args ...)
{}
我刚刚检查了 clang/gcc,重载运算符被二进制表达式 (a+b
) 和一元表达式 (+a
) 拾取,如我所料。然而,运算符比普通函数更受限制,例如 - 你不能用三个参数重载 operator+()
。
以上用法是否合法且可移植?
EDIT 为了提供一些上下文,我显然不希望能够定义可变参数运算符或任何类似的东西。我对此感兴趣的原因是一个丑陋的 hack:我想让一些运算符可变,这样我就可以 "override" 它们与其他非可变实现。由于可变参数模板在函数模板重载规则中被认为不如非可变参数模板专业,因此我可以用非可变参数操作符覆盖可变参数操作符。是的,这太可怕了:)
首先,定义很好,因为存在非空包的有效特化1。
现在,特定表达式 a+b
或 +a
是 i.a。分别转换为 operator+(a, b)
和 operator+(a)
形式的非成员调用([over.match.oper]/2). Name lookup then finds the operator function template, whose specialization becomes part of the candidates. Finally, [over.match.oper]/6 只是像往常一样委托重载决策:
The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates. The argument list contains all of the operands of the operator. The best function from the set of candidate functions is selected according to 13.3.2 and 13.3.3.
您的代码也将按预期工作,因为重载解析和部分排序将像所有其他代码一样遵守运算符函数模板。
1 为一元运算符声明以上内容,可能除了后缀 --
和 ++
之外,格式错误,不需要诊断。比照。 [temp.res]/(8.2).
标准限制 运算符函数 的参数数量(以及默认参数的存在),在 [over.oper]:
中8 - An operator function cannot have default arguments ([dcl.fct.default]), except where explicitly stated below. Operator functions cannot have more or fewer parameters than the number required for the corresponding operator, as described in the rest of this subclause.
但是,您声明的是运算符函数模板,没有这样的限制。这意味着您的代码没问题;一元或二进制 +
的使用将转换为使用一个或两个参数调用 operator+
,并相应地生成模板的适当实例化。
如果您使用非法数量的参数专门化或显式实例化运算符函数模板,那将是非法的,因为 ([over.oper]):
1 - [...] A specialization of an operator function template is also an operator function. [...]
请注意,如果我们编写一个可以用不正确类型实例化的非可变运算符函数模板,则会产生类似的效果:
template<class T> int operator+(T, T) { return 0; } // OK
struct bar {}; template int operator+(bar, bar); // OK
template int operator+(int, int); // Error is here