-
Notifications
You must be signed in to change notification settings - Fork 75
Description
Hi,
I have the following function defined on my code:
template <typename Resource>
auto load()
{
std::vector<std::string>assetFilenames{ "img1.jpg", "img2.jpg" };
std::vector<stlab::future<Resource>> tasks;
//1 task per file
for( auto i = 0u; i < assetFilenames.size(); ++i )
{
tasks.push_back( stlab::async( stlab::default_executor, [f = std::move( assetFilenames[i] )]
{
return Resource{ f };
} ) );
}
return stlab::when_all( stlab::default_executor, []( auto&& results )
{
return results;
}, std::make_pair( tasks.begin(), tasks.end() ) );
}
Resource represents a class that is move-only, my engine relies A LOT in objects like this, e.g. Texture, VertexBuffer etc are all move-only objects. For illustration purposes I am going to define a move-only class called Dummy:
struct Dummy
{
Dummy() = default;
~Dummy() = default;
explicit Dummy( const string& filename )
: filename{ filename }{}
Dummy( Dummy&& ) = default;
Dummy& operator=( Dummy&& ) = default;
public:
string filename;
};
If I do the following with a copyable type like std::string, things work perfect( NOTE: I know we shouldn't use blocking_get(), but it's just for illustration purposes )
auto cache = blocking_get( load<string>( ) );
Unfortunately if I use a move-only object the program fails to compile
auto cache = blocking_get( load<Dummy>( ) );
The compilation error happens here
template <typename R, typename C>
struct create_range_of_futures {
template <typename S, typename F, typename I>
static auto do_it(S&& s, F&& f, I first, I last) {
assert(first != last);
auto context = std::make_shared<C>(std::forward<F>(f), std::distance(first, last));
auto p = package<R()>(std::move(s), [_c = context] { return _c->execute(); });
context->_f = std::move(p.first);
size_t index(0);
std::for_each(first, last,
[&index, &context](auto item) { attach_tasks(index++, context, item); }); //Compilation error here: It tries to copy a future<Dummy> into item, but it doesnt succeed
return std::move(p.second);
}
};
Of course I could use shared_ptr as a workaround:
template <typename Resource>
auto load2()
{
std::vector<std::string>assetFilenames{ "img1.jpg", "img2.jpg" };
std::vector<stlab::future<shared_ptr<Resource>>> tasks;
//1 task per file
for( auto i = 0u; i < assetFilenames.size(); ++i )
{
tasks.push_back( stlab::async( default_executor, [f = std::move( assetFilenames[i] )]
{
return make_shared<Resource>( f );
} ) );
}
return when_all( default_executor, []( auto&& results )
{
return results;
}, make_pair( tasks.begin(), tasks.end() ) );
}
vector<Dummy> cache;
for( auto& elem : blocking_get( load2<Dummy>() ) )
cache.emplace_back( move( *elem ) );
...but obviously this solution is not very elegant :(. Could you please let me know if there is a better solution to this problem?
Thanks,