Как разработать типы, необходимые для функции std:: for_each lambda

Я запутался в том, как определить, какой тип требуется для использования лямбда-функции в std::for_each. Кажется, я не могу использовать auto в этом случае в качестве параметра (Visual Studio 2013 жалуется в любом случае).

В коде ниже я бы подумал, что буду использовать разделы в качестве типа для функции for_each, но на самом деле я должен использовать

const std::pair<std::string, std::unordered_map<std::string, std::string> >

А для «внутреннего» типа в данном случае что я использую?

Мой главный вопрос заключается в том, как я работаю, какой тип использовать?

#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>


// key=value pairs within a section
typedef std::unordered_map<std::string, std::string> keyvalue;

// [section1] - top level
typedef std::unordered_map< std::string, std::unordered_map<std::string, std::string> > sections;

class config
{
public:
    config() {
        setup();
    }
    typedef sections::iterator iterator;
    iterator begin() { return sections_.begin(); }
    iterator end() { return sections_.end(); }


private:
    sections sections_;

    void setup() { 
        // obviously we wouldn't hard code like this in a real program
        sections_["programming languages"].insert(std::make_pair("C", "imperative"));
        sections_["programming languages"].insert(std::make_pair("C++", "OOP"));
        sections_["programming languages"].insert(std::make_pair("Java", "OOP"));
        sections_["programming languages"].insert(std::make_pair("Haskell", "functional"));
        sections_["programming languages"].insert(std::make_pair("Prolog", "logic"));
    }
};


int main() {
    config cfg;
    std::for_each(cfg.begin(), cfg.end(), [](const std::pair<std::string, std::unordered_map<std::string, std::string> > sec) {
        std::cout << "section name: " << sec.first << std::endl;

        // what is inner type - thought it would be keyvalue ???
        //std::for_each(sec.second.begin(), sec.second.end(), [](const keyvalue& pr) {   
            //std::cout << "first: " << pr << std::endl;
        //});
    });

    // I thought type would be sections ???
    //std::for_each(cfg.begin(), cfg.end(), [](const sections& sec) {
    //  std::cout << "section name: " << sec.first << std::endl;
    //});
}

1 ответ

  1. Вы также можете использовать decltypeдля этой цели, как это:

        config cfg;
        std::for_each(cfg.begin(), cfg.end(), [](const decltype(*cfg.begin())& sec) {
            std::cout << "section name: " << sec.first << std::endl;
    
            std::for_each(sec.second.begin(), sec.second.end(), [](const decltype(*sec.second.begin())& pr) {   
            std::cout << "first: " << pr.first << std::endl;
            });
        });
    

    Я не на 100% уверен, как ссылочные типы влияют на это, поэтому удаление может быть более подходящим, как const std::remove_reference<decltype(*cfg.begin())>::type& sec

    Хотя следует отметить, что VS2013 ItelliSense имеет проблемы с decltype и пометит его как ошибку, даже если он компилируется нормально.

    Контейнеры STL всегда определяют value_typeтак, что в этом случае вы можете использоватьdecltype(inst)::value_type, и вам не нужны махинации remove_reference. Поэтому я бы посоветовал вам также добавить value_typetypedef к вашему типу, как это:

    class config
    {
    public:
        typedef sections::value_type value_type;
    

    Тогда вы можете сделать:

        config cfg;
        std::for_each(cfg.begin(), cfg.end(), [](const decltype(cfg)::value_type& sec) {
            std::cout << "section name: " << sec.first << std::endl;
    
            std::for_each(sec.second.begin(), sec.second.end(), [](const decltype(sec.second)::value_type& pr) {   
            std::cout << "first: " << pr.first << std::endl;
            });
        });