【问题标题】:std::initializer_list as right hand argument for overloaded operator?std::initializer_list 作为重载运算符的右手参数?
【发布时间】:2021-09-23 09:58:24
【问题描述】:

我想使用其他编程语言中可用的“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';
}

同样的道理,同样的问题。 . .

有什么办法可以做到吗?

【问题讨论】:

标签: c++ operator-overloading initializer-list


【解决方案1】:

大括号初始化列表只允许在某些上下文中被语法例外。虽然重载运算符涉及函数调用,但它仍必须遵守标准语法规则,除非您在函数调用中按名称 (operator@) 调用它。

所以您的命名运算符可以工作,但您必须重载其中存在异常的运算符之一1。这些可重载运算符的粗略总结是:

  • 分配,包括复合分配(operator=operator +=)。
  • 索引 (operator[])。
  • 函数调用 (operator())。

这些都不能作为非成员重载,因此不可能实现对称(&lt;is_in&gt;=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&lt; 来改善它的外观,但总的来说这似乎很愚蠢。这已经有点太晦涩了。


1 - 在这方面,您应该知道重载其参数是纯标准类型的运算符是不明智的。标准可以随时更改库定义,光荣地破坏你的代码。

【讨论】:

  • 补充说明。尽管如此,is_in= { 对我来说还是不自然
【解决方案2】:

您需要通过const&amp; 采取initializer_list

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';
}

【讨论】:

  • 是的,正确,谢谢。但我不想写 std::initializer_list{1,2,3,4,5} 而只是 {1,2,3,4,5} 。 . .
  • @ArminMontigny 我明白了。好的,那么这可能没有多大帮助。
猜你喜欢
  • 2011-01-22
  • 2017-01-04
  • 2013-06-14
  • 1970-01-01
  • 2018-12-23
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 2021-10-25
相关资源
最近更新 更多