使用 C++11 将指向成员函数的指针作为参数传递

Pass pointer to member function as argument with C++11

本文关键字:指针 参数传递 函数 成员 C++11 使用      更新时间:2023-10-16

为了优化下面的代码,在我看来,如果我可以将指向str1str2成员函数之一的指针作为fill_vec的参数传递,而不是在fill_vec中有两个显式循环,那将是有益的。

在 C++11 中是否有首选方法?或者你建议不同的策略?


#include <iostream>
#include <vector>
#include <map>
class Base
{
private:
std::map<int, std::string> m_base1, m_base2;
std::vector<std::string> m_str1 = {"one", "two", "three"};
std::vector<std::string> m_str2 = {"four", "five", "six"};
public:
std::vector<std::string> &str1() { return m_str1; }
std::vector<std::string> &str2() { return m_str2; }
std::map<int, std::string> &base1() { return m_base1; }
std::map<int, std::string> &base2() { return m_base2; }
};
template <typename T>
void fill_vec(T *b)
{
size_t counter = 0;
for (const auto &str_iter : b->str1())
(b->base1())[counter++] = str_iter;
counter=0;
for (const auto &str_iter : b->str2())
(b->base2())[counter++] = str_iter;
}
int main(int argc, char *argv[])
{
Base *b = new Base;
fill_vec(b);
return 0;
}

建议的做法将规定fill_vec()应该是 Base 的成员,最好从构造函数调用,以便对象在创建后立即可以使用。

但是,由于映射m_base1和m_base2是常量,因此您应该取消m_str1和m_str2,将m_base1和m_base2设置为静态,并直接在构造函数中初始化它们。

而且,您应该尽可能使用智能指针。

这给出了:

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <memory>
class Base
{
private:
static std::map<int, std::string> m_base1, m_base2;
public:
Base();  // WARNING !! must create a object before using maps!
static const auto & base1() { return m_base1; }
static const auto & base2() { return m_base2; }
};

// in base.cpp
std::map<int, std::string> Base::m_base1;
Base::Base()
{
if (m_base1.empty())
{
m_base1[0] = "one";
m_base1[1] = "two";
m_base1[2] = "three";
}
if (m_base2.empty())   
{
m_base2[0] = "four";  // doesn't look right, but equivalent to original code
m_base2[1] = "five";
m_base2[2] = "six";
}
}

// in your main module..
int main(int argc, char *argv[])
{
// auto b = std::unique_ptr<Base>(new Base{});
// this would be best since Base is very small.
Base b;
// this prints the string "two six"
std::cout << b.base1().at(1) << " " << b.base2().at(2) << 'n';
return 0;
}

这是可能的,但我会根据上面的评论检查它的实用性。

这样的东西会起作用:

template <typename T>
void fill_vec(Base* obj, std::map<int, std::string>& (T::*mapv)(), std::vector<std::string>& (T::*vec)())
{
size_t counter = 0;
for (const auto &str_iter : (obj->*vec)())
(obj->*mapv)()[counter++] = str_iter;       
}
int main(int argc, char *argv[])
{
Base *b = new Base;
fill_vec(b, &Base::base1, &Base::str1);
return 0;
}

这与通常传递pointer to member fields的工作方式类似