运算符能否重载用于初始化列表字面量?

10

我正在尝试为std::initializer_list重载运算符,但是以下代码无法在GCC 4.7.2和Clang 3.2中编译:

#include <initializer_list>

void operator+(const std::initializer_list<int>&, const std::initializer_list<int>&);

int main() {
   {1, 2} + {3, 4};
}

13.5/6规定:运算符函数至少应当有一个参数,其类型为类、枚举或者是指向它们的引用。标准将initializer_list定义为模板类,所以我认为这个代码应该符合规范。然而,显然Clang和GCC都认为我正在尝试使用它们非标准的块表达式。

GCC:

Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:7:8: warning: left operand of comma operator has no effect [-Wunused-value]
source.cpp:7:9: error: expected ';' before '}' token
source.cpp:7:9: warning: right operand of comma operator has no effect [-Wunused-value]
source.cpp:7:13: error: expected primary-expression before '{' token
source.cpp:7:13: error: expected ';' before '{' token

Clang:

Compilation finished with errors:
source.cpp:7:5: warning: expression result unused [-Wunused-value]
   {1, 2} + {3, 4};
    ^
source.cpp:7:9: error: expected ';' after expression
   {1, 2} + {3, 4};
        ^
        ;
source.cpp:7:8: warning: expression result unused [-Wunused-value]
   {1, 2} + {3, 4};
       ^
source.cpp:7:13: error: expected expression
   {1, 2} + {3, 4};
            ^
2 warnings and 2 errors generated.

这段代码是否可以编译?如果不能,为什么?

编辑:

并且毫不意外的是,VS 2012的十一月版CTP也失败了:

error C2143: syntax error : missing ';' before '}'
error C2059: syntax error : '{'
error C2143: syntax error : missing ';' before '{'
1个回答

6
据我理解,13.5/6规定:运算符函数必须是非静态成员函数或者是非成员函数,并且至少有一个参数的类型为类、类的引用、枚举或枚举的引用。然而,这不应该是可能的。花括号初始化列表与std::initializer_list不同,也不能互换使用。但下面的代码应该可以正常工作:
std::initializer_list<int>({1,2}) + std::initializer_list<int>({2,1})

或者是这样的:
operator+({1,2}, {2,1})

更新:澄清一下,这个观点的重点在于,语言语法中没有规定大括号初始化列表可以出现在OP建议的上下文中。如果说要初始化某些东西,大括号初始化列表只能出现在特定的上下文中。


3
你尝试过使用 std::initializer_list<int>({1,2}) + std::initializer_list<int>({2,1}) 了吗?花括号列表本身不是初始化列表,只能在某些情况下(例如 auto 推导)用于定义一个初始化列表。 - Kerrek SB
1
@KerrekSB 那么什么时候大括号初始化器会变成 std::initializer_list?我猜这就是问题的关键。 - Seth Carnegie
例如,当你说auto x = {1, 2, 3};时,x的类型是std::initializer_list<int>。但这些规则在8.5中是单独规定的;否则,花括号列表不像标识符和字面量那样是一等实体。 - Kerrek SB
@Potatoswatter:但语法在那个位置不期望出现花括号初始化列表。你可以尝试使用operator+({1,2}, {2,1}),但这仅适用于当前代码,例如template <typename T> void operator+(T, T)就无法使用。 - Kerrek SB
1
@KerrekSB 啊,没错。我认为这应该是答案的第一部分...说一个带大括号初始化列表不同于std::initializer_list有点像说整数字面量不同于int。但语法期望的是赋值表达式,而不是初始化器子句,后者包括赋值表达式带大括号初始化列表 - Potatoswatter
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接