【问题标题】:How can I send a variable number of pairs of variables to a function如何将可变数量的变量对发送到函数
【发布时间】:2020-07-26 23:08:12
【问题描述】:

我正在尝试写类似这样的东西:

void loadImage(SDL_Renderer *ren, {SDL_Texture *&texture, const char *imagePath} ... ){
    for(int i = 0; i < numOfPairs; i++){
        SDL_Surface *curImage = IMG_Load(pairs[i].second);
        pairs[i].first = SDL_CreateTextureFromSurface(ren, curImage);
        SDL_FreeSurface(curImage);
    }
}

我有可变数量的对,每对包含一个纹理及其对应的路径。我不知道,哪种方式最好解决这个问题。我曾考虑过使用 &lt;cstdarg&gt; 库的可变参数函数,但我在另一个问题上读到这不是一个好的解决方案。

【问题讨论】:

    标签: c++ parameter-passing variadic-functions


    【解决方案1】:

    立即想到的方式是std::vector。如果您使用的是 c++11 或更好的编译器,则可以传递 std::pair 或 std::tuple 的向量。

    做起来很简单

    #include <vector>
    #include <tuple>
    
    ....
    
    
    std::vector<std::tuple<SDL_texture, const char *>> args;
    
    args.push_back(std::make_tuple(texture1, path1));
    args.push_back(std::make_tuple(texture2, path2));
    

    然后你的功能

        void load_Image(SDL_renedred *ren, const std::vector<std::tuple<SDL_texture, const char *>> &args)
        {
             std::tuple<SDL_textture, const char*> &arg1 = args[0];
      // or if you have modern c++
             auto &arg1 = args[0];  
        }
    

    (未编译,可能有错别字。)

    【讨论】:

      【解决方案2】:

      虽然我很讨厌,但你可以使用std::initializer_list like:

      #include <initializer_list>
      #include <tuple>
      
      void loadImage(SDL_Renderer *ren, std::initializer_list<std::tuple<SDL_Texture*&,const char *&>> pair_list ){
          for(auto p:pairlist){//initializer_list cannot be indexed but only iterated
              SDL_Surface *curImage = IMG_Load(p.second);
              p.first = SDL_CreateTextureFromSurface(ren, curImage);
              SDL_FreeSurface(curImage);
          };  
      };
      
      //call site:
      loadImage(ren,{tie(tex1,path1),tie(tex2,path2),tie(tex3,path3)});
      

      建议使用服装删除器将指针存储在std::unique_ptr 瞬间。而且我想你最好改变你的数据结构设计以避免像那样绑定对象 - 例如使用std::map:

      #include <initializer_list>
      #include <memory>
      #include <map>
      
      struct MySDLDeleter{
          void operator(SDL_Texture* texPtr){SDL_FreeTexture(texPtr);};
          void operator(SDL_Renderer * renPtr){SDL_FreeRenderer(renPtr);};
          void operator(SDL_Surface * srfPtr){SDL_FreeSurface(srfPtr);};
      };
      
      auto loadImage(std::unique_ptr<SDL_Renderer,MySDLDeleter> ren, std::initializer_list<const char *> path_list ){
          std::map<const char *,std::unique_ptr<SDL_Texture,MySDLDeleter> texMap;
          for(auto p:path_list ){
              std::unique_ptr<SDL_Surface ,MySDLDeleter> curImage = IMG_Load(p.second);
              texMap.insert(p,SDL_CreateTextureFromSurface(ren.get(), curImage.get()));
          }; 
          return texMap; 
      };
      
      //call site:
      auto texMap=loadImage(create_the_renderer_ptr(),{path1,path2,path3});
      

      【讨论】:

        【解决方案3】:

        首先编写一个函数来处理每一对(即你的 for 循环中的内容):

        using ImagePair = std::pair<SDL_Texture*&, const char*>;
        
        void processImage(ImagePair imgPair)
        {
            SDL_Surface *curImage = IMG_Load(imgPair.second);
            imgPair.first = SDL_CreateTextureFromSurface(ren, curImage);
            SDL_FreeSurface(curImage);
        }
        

        如果你有 C++11 或更高版本,你可以使用大括号初始化技巧为每个参数调用 processImage()

        template <typename ... Ts>
        void loadImage(Ts ... ts)
        {
            using dummy = int[];
            (void)dummy {0, (processImage(ts)), 0)... };
        }
        

        您在这里所做的是利用编译器知道它必须在大括号初始化列表中进行包扩展这一事实。这样您就可以避免自己编写递归可变参数模板函数。

        在这里,您正在构建一个虚拟整数数组,其大小等于您传入的可变参数的数量。对于每个参数,您调用函数processImage(),但使用逗号运算符设置值数组为 0。因此,您展开包并在创建虚拟数组时为每个参数调用 processImage()。这个answer 可能会解释得更清楚。

        如果你有 C++17 或更高版本,你可以进一步简化并使用折叠表达式:

        template<typename... Ts>
        void loadImage(Ts... args)
        {
            (processImage(args),...);
        }
        

        【讨论】:

        • 我想请教一下... = { (processImage(ts), 0)... }; 的解释,因为我觉得这超出了我的想象。
        • @SandWoodJones 我在上面添加了解释。希望有用。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-01
        • 2012-11-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多