将lambdas直接传递给函数

时间:2018-02-25 01:45:42

标签: c++ c++11

我正在编写一个import pandas as pd ... # Function for creating pandas dataframes from SQL-statements def sqlToFrame(sql): db = ibm_db.connect(connection_string, "", "") con = ibm_db_dbi.Connection(db) return pd.read_sql(sql, con, params = (u'Å',)) df = sqlToFrame("SELECT * FROM DATA_CONFIG WHERE TAG_NAME = ?") 类,表示可能存在或不存在的值。 Option函数用于获取if_opt和一个函数,该函数将在Option中保存的值上调用,但仅在值存在时才会调用。

Option

我注意到如果我这样使用它会有效:

template <class T>
class Option {
private:
    std::shared_ptr<T> m_value;
public:
    explicit operator bool()const noexcept
    {
        return (bool)m_value;
    }

    Option() = default;

    explicit Option(T value)
    {
        m_value =  std::make_shared<T>(value);
    }

    template <class U>
    friend void if_opt(Option<U>&, std::function<void(U&)>);
};

template <class T>
void if_opt(Option<T>& opt, std::function<void(T&)> f)
{
    if (opt) f(*opt.m_value);
};

但是我希望能够将lambda表达式直接放在调用中,但是当我这样做时:

Option<int> none;
Option<int> some(10);

function<void(int&)> f1 = [](int& none)
{
    cout << "This should never be reached" << endl;
};

function<void(int&)> f2 = [](int& some)
{
    cout << "The value of some is: " << some << endl;
};

if_opt(none, f1);

if_opt(some, f2);

我收到错误:

if_opt(none, [](int&)
{
    cout << "This should never be reached" << endl;
});

if_opt(some, [](int& some)
{
    cout << "The value of some is: " << some << endl;
});

我知道lambda表达式的类型在标准中是未定义的,并且它只需要分配给error: no matching function for call to 'if_opt(Option<int>&, main()::<lambda(int&)>)' ,所以这种方法是有意义的,但有没有办法让我可以得到lambda参数隐式转换为std::function<R(T)>,以便我可以按照我尝试的方式调用std::function<void(T&)>中的lambda?

1 个答案:

答案 0 :(得分:2)

std::function<Sig>是一种类型擦除工具。它会删除(几乎)关于它存储的值的所有内容,可以使用Sig调用它。

模板参数推导采用传入类型并推导出应该使用的类型,然后生成并(通常)调用模板函数。

这些几乎是彼此的反转。对类型擦除模板进行演绎是代码嗅觉,几乎总是一个坏主意。

这是你的基本设计错误。

有许多方法可以修复您的代码。

首先,if_opt不应该是模板。

friend void if_opt(Option<T>& opt, std::function<void(T&)> f){
  if (opt) f(*opt.m_value);
}

这创造了我称之为Koenig的朋友。您必须内联定义主体。实际上,U类型毫无意义,甚至可能在某些情况下导致错误。

但这里的类型擦除也毫无意义。修复返回模板,但现在有充分的理由。

template<class F>
friend void if_opt(Option<T>& opt, F&& f){
  if (opt) f(*opt.m_value);
}

这是一个更好的设计。

你可以去投资SFINAE重载解析代码,但我不会打扰。

template<class F,
  std::conditional_t<true, bool,std::result_of_t<F&(T&)>> = true
>
friend void if_opt(Option<T>& opt, F&& f){
  if (opt) f(*opt.m_value);
}

以上是模糊的,并且与上面的优势相比具有最小的边际优势。