我正在嘗試從基本函式轉發通用引數包,但這樣做很麻煩,特別是如果型別串列中有非文字非參考型別
考慮以下示例:
#include <utility>
#include <iostream>
#include <future>
#include <vector>
template < typename... Args >
class BaseTemplate {
public:
BaseTemplate() = default;
virtual ~BaseTemplate() = default;
virtual std::future< void > call(Args... args) {
return std::async(std::launch::async, [this, &args... ] {
// ..
first(std::forward<Args>(args)...);
second(std::forward<Args>(args)...);
third(std::forward<Args>(args)...);
// ...
});
}
protected:
virtual void first(Args...) { /* ... */ }
virtual void second(Args...) = 0;
virtual void third(Args...) { /* ... */ }
};
class SomeType {
public:
explicit SomeType(std::vector< float >* data) : ptr(data) { /* ... */ }
~SomeType() = default;
// ...
// protected:
float member = 5.6;
std::vector< float >* ptr;
};
class Derived1 : public BaseTemplate< int, float, SomeType > {
public:
using Base = BaseTemplate< int, float, SomeType >;
Derived1() : Base() { /* ... */ }
~Derived1() = default;
protected:
void second(int, float, SomeType obj) override {
std::cout << "Derived1::" << __func__ << " (" << obj.member << ")" << std::endl;
printf("%p\n", obj.ptr);
for (const auto& val : *(obj.ptr)) {
std::cout << val << std::endl;
}
}
};
class Derived2 : public BaseTemplate< int, float, const SomeType& > {
public:
using Base = BaseTemplate< int, float, const SomeType& >;
Derived2() : Base() { /* ... */ }
~Derived2() = default;
protected:
void second(int, float, const SomeType& obj) override {
std::cout << "Derived2::" << __func__ << " (" << obj.member << ")" << std::endl;
printf("%p\n", obj.ptr);
for (const auto& val : *(obj.ptr)) {
std::cout << val << std::endl;
}
}
};
int main(int argc, char const *argv[]) {
std::vector< float > data {0, 1, 2, 3};
SomeType obj(&data);
Derived1 foo1;
Derived2 foo2;
// auto bar1 = foo1.call(1, 5.6, obj); // Segmentation fault
auto bar2 = foo2.call(1, 5.6, obj); // OK
// ...
// bar1.wait();
bar2.wait();
return 0;
}
一切正常,如果按預期SomeType按參考傳遞,但段錯誤如果按值傳遞。std::forward<>()為了解決這兩種情況,正確的使用方法是什么?
uj5u.com熱心網友回復:
問題不在于std::forward電話;程式在到達它們之前表現出未定義的行為。call通過值獲取一些引數,但內部的 lambda 始終通過參考捕獲它們。因此,它最終持有對區域變數的參考,這些變數在call回傳后立即被銷毀- 但 lambda 稍后會被呼叫,可能在不同的執行緒上。那時,所有這些參考都是懸空的——不僅是對 的參考SomeType,還有對int和對的參考float。
一種可能的解決方案可能是這樣的:
virtual std::future< void > call(Args... args) {
std::tuple<BaseTemplate*, Args...> t{this, args...};
return std::async(std::launch::async, [t] {
// ..
std::apply(&BaseTemplate::first, t);
std::apply(&BaseTemplate::second, t);
std::apply(&BaseTemplate::third, t);
// ...
});
}
我們將引數存盤在一個元組中——通過值傳遞的引數的副本,對通過參考傳遞的引數的參考。然后 lambda 按值捕獲此元組,并將std::apply其組件傳遞給被呼叫的實際函式。
演示
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/407745.html
標籤:
上一篇:Tornado&Apache反向代理無法獲得正確的配置
下一篇:缺少Default.aspx表單
