【问题标题】:Variadic operator overloading of the [] in C++C++ 中 [] 的可变参数运算符重载
【发布时间】:2022-01-19 14:43:38
【问题描述】:

我希望使用运算符 [] 中传递的表达式。我认为使用可变模板参数可以解决问题,但我错了...... 是在 c++11 中做到这一点的一种方法吗?

class object {
 

private:


public:
  void values() { std::cout << "finished" << std::endl; }
  template <typename T, typename... Type> void values(T arg, Type... args) {

    std::cout << arg << "  " << std::endl;
    values(args...);
  }


   template<typename... Type> void operator[](Type... args) {

       values(args...);
  }
};

int main(void) {
  object o1 = object();

  o1.values(1, 6.2, true, "hello"); // Works fine.
  
  o1[1, 6.2, true]; // Only the last value gets printed eg. true
  

  return 0;
}

更广泛的目标是我被要求为此制定一个有效的语法

let o3 = object [ values 1, "2", true, -3.14 ];
let o1 = object [  key("x") = -1, key("y") = -2,values 1, "2", true, -3.14 ]; // no commas are missing

在 c++11 中使用 c++11 STL(模板、使用、宏、运算符重载等)。我正在慢慢尝试弄清楚如何将这些拼凑起来

【问题讨论】:

  • operator[] 只接受一个参数(至少在 C++23 之前)。
  • 无赖...还有其他方法可以实现吗?
  • 如果你用o1.operator[](...);调用它,它会给你一个编译时错误:godbolt.org/z/Ghvhvhese你的版本只能编译,因为逗号运算符丢弃了第一个和第二个值。
  • 您可以改用operator(),它可以有任意数量的参数。
  • 这样做的目的是什么?您始终可以使用命名方法而不是运算符。可以玩一些技巧,例如o1[ some_magic(1),6.2, true] 会起作用,但我认为无法启用o1[1,6.2,true]

标签: c++ c++11 templates operator-overloading


【解决方案1】:

首先,您需要了解operator[] 只能接受一个参数。您的模板化运算符隐藏了一条非常清楚的错误消息。

struct foo {
    void operator[](int,int);
};

导致错误:

<source>:2:10: error: 'void foo::operator[](int, int)' must have exactly one argument
    2 |     void operator[](int,int);
      |          ^~~~~~~~

您可以将其设为可变参数模板,但任何不完全是一个参数的实例化都是不正确的。


弗兰克,这听起来像是一个诡计的问题。编写 C++ 代码时,最好使用 C++ 语法。如果允许使用宏(它们不应该),那么几乎一切皆有可能。您只需要知道您实际上不再是在编写 C++。此外,仅仅要求编译一些语法似乎有点奇怪。我不知道 javascript,也不确定这两行应该是什么意思,所以我只这样做了:让它以某种方式编译。

不管怎样,让我们​​看看能做些什么。

let o3 = object [ values 1, "2", true, -3.14 ];

我想这声明o3 是一个对象,其初始化程序是从一个名为object 的容器中检索的,该容器可以通过values 1, "2", true, -3.14 进行索引。可以通过重载一些operator,#defineing letautovalues 来编译该行,以构造一个收集索引的对象(通过其operator,):

第二行

let o1 = object [  key("x") = -1, key("y") = -2,values 1, "2", true, -3.14 ]; 

operator, 和滥用key::operator= 可以玩类似的把戏。我将key 解释为构造一些键值对,例如key("x") = -1 将值-1 映射到字符串"x"。它实际上所做的对于接下来的所有脏东西来说并不是必不可少的。一旦您了解了如何滥用运算符重载,就可以对其进行修改以在细节上做其他事情。

要查看所有值实际上都传递给operator[],我从这里偷了一些元组打印函数:https://stackoverflow.com/a/41171552/4117728

#include <tuple>
#include <string>
#include <typeinfo>
#include <iostream>
#define let auto
//https://stackoverflow.com/a/41171552/4117728
template<class TupType, size_t... I>
void print(const TupType& _tup, std::index_sequence<I...>)
{
    std::cout << "(";
    (..., (std::cout << (I == 0? "" : ", ") << std::get<I>(_tup)));
    std::cout << ")\n";
}

template<class... T>
void print (const std::tuple<T...>& _tup)
{
    print(_tup, std::make_index_sequence<sizeof...(T)>());
}
//........................................

struct Object {
    template <typename ...T>
    struct ObjectIndex {
        ObjectIndex() {}
        ObjectIndex(std::tuple<T...> ind) : index(ind) {}
        std::tuple<T...> index;        
        template <typename U> 
        ObjectIndex<T...,U> operator,(const U& u){ 
            return { std::tuple_cat(index,std::make_tuple(u)) };
        }
        template <typename...U>
        ObjectIndex<T...,U...> operator,(const ObjectIndex<U...>& other) { 
            return { std::tuple_cat(index,other.index) };
        }
    };
    template <typename ...T>
    int operator[](ObjectIndex<T...> index){
        std::cout << typeid(index.index).name() << "\n";
        print(index.index);
        return 42;
    }
};

struct key {
    std::string k;
    int val;
    key(const std::string& s) : k(s) {}
    Object::ObjectIndex<std::string,int> operator=(int v) {
        val = v;
        return {std::make_tuple(k,val)};
    }

};

#define values Object::ObjectIndex<>{} ,

int main() {
    Object object;
    let o3 = object [ values 1, std::string("2"), true, -3.14 ];
    let o1 = object [  key("x") = -1, key("y") = -2,values 1, std::string("2"), true, -3.14 ]; 
}

Live Demo

不要在家里(或其他任何地方)这样做!

传递字符串文字存在一些问题,我没有费心去进一步研究,所以我允许自己将"2" 替换为std::string("2")。我想通过无休止的错误消息进行更多战斗,这也可以解决。

我不知道代码是否接近这两行真正应该做的事情。我只是把它当作一个有趣的练习来让它以某种方式编译。当实际从operator[] 返回一些东西时,我的想法已经用完了。我很难想象一个具有真正可变参数operator[] 的容器。我总是选择正确的答案。


TL;DR 你能重载operator[] 以获取多个参数吗?不可以。您可以重载它以采用封装任意值的单个参数吗?当然。

【讨论】:

  • 谢谢!不完全是我想要的,但这完全是我的错,它没有在 c++11 中编译。它有很多东西可以帮助我很多,主要是“你能重载它以采用一个封装的参数任意值?当然。部分!这是否与 &lt;&lt; 运算符重载抱怨它是二元运算符有关,但通过某些方式使其接受 2 个参数? (找到了一些使用friend 来实现这一点的方法)。再次感谢您的宝贵时间!
  • @Lampros 我不明白您所说的“&lt;&lt; 运算符重载”是什么意思。我将多个值传递给operator[] 的意思是,您可以传递std::vector&lt;int&gt;std::pair&lt;int,int&gt;std::tuple 或其他任何值
猜你喜欢
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-22
相关资源
最近更新 更多