[英]std::initializer_list alternatives for noncopyable types
I know that trying to use a std::initializer_list<NonCopyable>
leads to an error because the elements are copied into the temporary array represented by the initializer_list
. 我知道尝试使用
std::initializer_list<NonCopyable>
会导致错误,因为元素被复制到initializer_list
表示的临时数组中。 I have also read some explanation on why it would not be alright to have rvalue references in the list, which I'm fine with. 我还读了一些解释为什么在列表中有rvalue引用是不行的,我很好。
The problem is that I would like to pass noncopyable things not in order to move from them, but only const
-access them, so the argument about rvalues does not apply. 问题是我想传递不可复制的东西不是为了从它们移动,而只是
const
-access它们,所以关于rvalues的参数不适用。 What can I do to retain, if possible, the list initialization syntax and the reference semantics (no wrappers, no raw pointers)? 如果可能,我可以做什么来保留列表初始化语法和引用语义(没有包装器,没有原始指针)?
NonCopyable a{...}, b{...};
ListInitialized c{a, b};
I think I'm missing something extremely obvious here. 我想我错过了一些非常明显的东西。
Update: 更新:
This works(*), 这有效(*),
ListInitialized(std::initializer_list<std::reference_wrapper<NonCopyable>>) {...}
but won't accept rvalues. 但不接受右值。 It would be nice if I could simply pass a list of anything that could go into
const NonCopyable&
. 如果我能简单地传递一个可以进入
const NonCopyable&
的任何东西的列表,那将是很好的。
(*) I know I wrote "no wrappers" but this affects neither the calling code nor the iteration over the list. (*)我知道我写了“没有包装器”但这既不影响调用代码也不影响列表上的迭代。
You can give ListInitialized
a variadic constructor template: 您可以为
ListInitialized
提供可变参数构造函数模板:
struct ListInitialized
{
template <class... T>
ListInitialized(const T... &arg);
};
If you need to make sure it can only be instantiated with the correct type, consider suitable SFINAE : 如果您需要确保它只能使用正确的类型进行实例化,请考虑使用合适的SFINAE :
struct ListInitialized
{
template <
class... T,
class Sfinae = std::enable_if_t<std::is_same<std::decay_t<T>, NonCopyable> &&...
>
ListInitialized(const T... &arg);
};
In addition to the comments and answers above, I found that this minimalistic wrapper fulfills my needs: 除了上面的评论和答案,我发现这个简约的包装器满足了我的需求:
#include <initializer_list>
#include <utility>
struct S {
S() { }
S(const S&) = delete; // Non-copyable
void f() const { }
};
template<class T>
class const_reference_wrapper {
public:
const_reference_wrapper(const T& ref_) : ref(ref_) { }
operator const T&() const { return ref; }
private:
const T& ref;
};
struct T {
T(std::initializer_list<const_reference_wrapper<S>> l) : c(l.size()) {
for(const S& i : l) // note: const auto& can't be used here, but it would be the same for std::reference_wrapper
i.f(); // we can do something with the elements
}
int c;
};
int main() {
S a, b;
T t{a, b, S{}}; // we can mix lvalues and rvalues with a natural syntax
return t.c; // correctly returns 3
}
Of course, care needs to be taken to ensure that any rvalue passed through this will live through the time it is being referenced. 当然,需要注意确保通过它的任何右值都将在其被引用的时间内存在。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.