std::initializer_list 作为重载运算符的右手参数?
std::initializer_list as right hand argument for overloaded operator?
我想使用其他编程语言中可用的类似“in”运算符的东西。我已经阅读了很多关于此的帖子。但是,没有什么能满足我的需要。
我想做的有点不同。请看下面第一个例子:
#include <iostream>
#include <initializer_list>
#include <algorithm>
bool operator ==(const int lhs, std::initializer_list<int>& il) {
return std::find(il.begin(), il.end(), lhs) != il.end();
}
int main() {
std::initializer_list<int> il{1,2,3,4,5};
std::cout << (3 == il) << '\n';
// std::cout << (3 == {1,2,3,4,5}) << '\n'; // Does not compile
}
但这不编译。大概是因为初始化器列表不是表达式。虽然也有例外。 std::initializer_list
可能是一个函数参数,尽管这里也需要表达式。
而且由于任何运算符基本上也是一个函数,我希望我也可以使用 std::initalizer_list
作为参数。
但是我不能。
我尝试了相同的方法,通过滥用 2 个运算符的重载来定义自己的 operator
和名称。见下文:
#include <iostream>
#include <vector>
// New operator: is_in
enum { is_in };
int operator < (const int& lhs, decltype(is_in)) { return lhs; }
int operator > (int lhs, std::vector<int>& rhs) { return std::find(rhs.begin(), rhs.end(), lhs) != rhs.end();}
int operator > (int lhs, std::initializer_list<int>& rhs) { return std::find(rhs.begin(), rhs.end(), lhs) != rhs.end(); }
int main() {
std::vector validValues{ 1, 2, 3, 4, 5 };
bool b = (5 <is_in> validValues);
// bool b = (5 <is_in> { 1, 2, 3, 4, 5 }); // Does not compile
std::cout << b << '\n';
}
同样的原理,同样的问题。 . .
有什么方法可以做到这一点吗?
您需要 initializer_list
const&
:
bool operator==(const int lhs, const std::initializer_list<int>& il)
std::cout << (3 == std::initializer_list{1,2,3,4,5}) << '\n';
对于 is_in
测试,您可以重载逗号运算符并执行如下操作:
template<class T>
struct is_in {
is_in(const std::initializer_list<T>& il) : ref(il) {}
const std::initializer_list<T>& ref;
};
template<class T>
bool operator,(const T& lhs, const is_in<T>& rhs) {
return std::find(rhs.ref.begin(), rhs.ref.end(), lhs) != rhs.ref.end();
}
int main() {
bool b = (5, is_in{ 1, 2, 3, 4, 5 });
std::cout << b << '\n';
}
大括号初始列表仅在特定上下文中被语法例外允许。虽然重载运算符涉及函数调用,但它仍必须遵守标准语法规则,除非您在函数调用中按名称 (operator@
) 调用它。
因此您的命名运算符 可以 工作,但您必须重载其中一个存在异常的运算符 1。这些可重载运算符的粗略总结是:
- 赋值,包括复合赋值(
operator=
、operator +=
)。
- 索引(
operator[]
)。
- 函数调用(
operator()
)。
其中 None 可能作为非成员重载,因此不可能获得对称性(<is_in>
或 =is_in=
)。但如果放弃,我们 can do 就像
#include <iostream>
#include <initializer_list>
inline constexpr class op {
template<typename T>
friend auto operator< (T const& t, op) {
struct {
T const & t;
bool operator=(std::initializer_list<T> il) {
return std::find(il.begin(), il.end(), t) != il.end();
}
} ret{t};
return ret;
}
} is_in;
int main() {
bool b = (5 <is_in= { 1, 2, 3, 4, 5 });
std::cout << b << '\n';
}
这不太漂亮...我想我们可以选择另一个运算符而不是 operator<
来改善它的外观,但总的来说这似乎很愚蠢。这已经有点太晦涩了。
1 - 在这方面,您应该知道重载其参数为纯标准类型的运算符是不明智的。标准可以随时更改库定义,光荣地破解你的代码。
我想使用其他编程语言中可用的类似“in”运算符的东西。我已经阅读了很多关于此的帖子。但是,没有什么能满足我的需要。
我想做的有点不同。请看下面第一个例子:
#include <iostream>
#include <initializer_list>
#include <algorithm>
bool operator ==(const int lhs, std::initializer_list<int>& il) {
return std::find(il.begin(), il.end(), lhs) != il.end();
}
int main() {
std::initializer_list<int> il{1,2,3,4,5};
std::cout << (3 == il) << '\n';
// std::cout << (3 == {1,2,3,4,5}) << '\n'; // Does not compile
}
但这不编译。大概是因为初始化器列表不是表达式。虽然也有例外。 std::initializer_list
可能是一个函数参数,尽管这里也需要表达式。
而且由于任何运算符基本上也是一个函数,我希望我也可以使用 std::initalizer_list
作为参数。
但是我不能。
我尝试了相同的方法,通过滥用 2 个运算符的重载来定义自己的 operator
和名称。见下文:
#include <iostream>
#include <vector>
// New operator: is_in
enum { is_in };
int operator < (const int& lhs, decltype(is_in)) { return lhs; }
int operator > (int lhs, std::vector<int>& rhs) { return std::find(rhs.begin(), rhs.end(), lhs) != rhs.end();}
int operator > (int lhs, std::initializer_list<int>& rhs) { return std::find(rhs.begin(), rhs.end(), lhs) != rhs.end(); }
int main() {
std::vector validValues{ 1, 2, 3, 4, 5 };
bool b = (5 <is_in> validValues);
// bool b = (5 <is_in> { 1, 2, 3, 4, 5 }); // Does not compile
std::cout << b << '\n';
}
同样的原理,同样的问题。 . .
有什么方法可以做到这一点吗?
您需要 initializer_list
const&
:
bool operator==(const int lhs, const std::initializer_list<int>& il)
std::cout << (3 == std::initializer_list{1,2,3,4,5}) << '\n';
对于 is_in
测试,您可以重载逗号运算符并执行如下操作:
template<class T>
struct is_in {
is_in(const std::initializer_list<T>& il) : ref(il) {}
const std::initializer_list<T>& ref;
};
template<class T>
bool operator,(const T& lhs, const is_in<T>& rhs) {
return std::find(rhs.ref.begin(), rhs.ref.end(), lhs) != rhs.ref.end();
}
int main() {
bool b = (5, is_in{ 1, 2, 3, 4, 5 });
std::cout << b << '\n';
}
大括号初始列表仅在特定上下文中被语法例外允许。虽然重载运算符涉及函数调用,但它仍必须遵守标准语法规则,除非您在函数调用中按名称 (operator@
) 调用它。
因此您的命名运算符 可以 工作,但您必须重载其中一个存在异常的运算符 1。这些可重载运算符的粗略总结是:
- 赋值,包括复合赋值(
operator=
、operator +=
)。 - 索引(
operator[]
)。 - 函数调用(
operator()
)。
None 可能作为非成员重载,因此不可能获得对称性(<is_in>
或 =is_in=
)。但如果放弃,我们 can do 就像
#include <iostream>
#include <initializer_list>
inline constexpr class op {
template<typename T>
friend auto operator< (T const& t, op) {
struct {
T const & t;
bool operator=(std::initializer_list<T> il) {
return std::find(il.begin(), il.end(), t) != il.end();
}
} ret{t};
return ret;
}
} is_in;
int main() {
bool b = (5 <is_in= { 1, 2, 3, 4, 5 });
std::cout << b << '\n';
}
这不太漂亮...我想我们可以选择另一个运算符而不是 operator<
来改善它的外观,但总的来说这似乎很愚蠢。这已经有点太晦涩了。
1 - 在这方面,您应该知道重载其参数为纯标准类型的运算符是不明智的。标准可以随时更改库定义,光荣地破解你的代码。