[英]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.