簡體   English   中英

從外部函數構造 std::function 給出 std::bad_function_call

[英]Constructing std::function from extern functions gives std::bad_function_call

我正在嘗試在 C++ 中制作純 Haskell 風格的 I/O。 它工作正常,但是當我重新組織一些定義時,我遇到了std::bad_function_call

這大約是觸發問題所需的時間:

//common.h

#include <functional>
#include <iostream>
#include <utility>
#include <string>

class Empty {};
class State {};

template <class A>
class IOMonad {
public:
  typedef std::function<std::pair<A, State> (State)> T;
};

template <class A, class B>
const auto bind(typename IOMonad<A>::T ma, std::function<typename IOMonad<B>::T (A)> f) {
  return [ma, f] (State state) {
    const auto x = ma(state);
    return f(x.first)(x.second);
  };
}

extern const IOMonad<std::string>::T getLine;
IOMonad<Empty>::T putLine(std::string str);
//externs.cpp

#include "common.h"

const IOMonad<std::string>::T getLine = [](State s) {
  (void)s;
  std::string str;
  std::cin >> str;
  return std::make_pair(str, State());
};

IOMonad<Empty>::T putLine(std::string str) {
  return [str] (State s) {
    (void)s;
    std::cout << str;
    return std::make_pair(Empty(), State());
  };
}
//main.cpp

#include "common.h"

const auto putGet = bind<std::string, Empty>(getLine, putLine);

int main() {
  (void)putGet(State());
  return 0;
}

使用此設置,我在調用putGet時得到一個std::bad_function_call 以前,我在main.cpp中包含了externs.cpp的內容,介於包括common.h和定義putGet之間,並且一切正常。 在不同的翻譯單元中擁有這些功能似乎導致了這個問題。 此外,如果我將函數保留在externs.cpp中,但我將putGet main的局部變量而不是全局變量,則不會發生這種情況。 造成異常 go 的另一件事是bind的定義折疊到putGet的定義中,如下所示:

const auto putGet = [] (State state) {
  const auto x = getLine(state);
  return putLine(x.first)(x.second);
};

為什么會這樣? std::function是否有一些我不知道的限制?

您與 static 初始化命令的失敗發生了沖突。 在您的情況下, getLine在用於初始化putGet時尚未初始化。

C++ 全局變量的基本規則是:全局變量的初始化不能依賴於其他編譯單元中的全局變量

雖然單個編譯單元中的全局變量按照它們定義的順序進行初始化,但不同編譯單元中的全局變量的初始化順序是未指定的。 不能保證getLine會在putGet之前被初始化(事實上,它似乎不是)。

要解決此問題,您需要(其中兩個您已經找到):

A.將putGet的初始化移到main中,保證getLine在使用前被初始化

或者

B. 不要在putGet的初始化中直接使用getLine (即將它包裹在額外的一層 lambda 中)。

或者

C。 使getLine成為實際的 function 而不是std::function持有 lambda。 C++ 中的對象和函數根本不同,並且具有不同的生命周期規則。 盡管有他們的名字, std::function是對象,而不是函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM