我知道尝试使用std::initializer_list<NonCopyable>
会导致错误,因为元素已复制到initializer_list
表示的临时数组中。我还阅读了一些解释,以解释为什么在列表中包含右值引用不是很好,我很好。
问题是我不想传递不可复制的东西,而不是为了传递它们,而只是const
-访问它们,因此关于rvalues的论点不适用。如果可能的话,我该怎么做才能保留列表初始化语法和引用语义(没有包装器,没有原始指针)?
NonCopyable a{...}, b{...};
ListInitialized c{a, b};
我想我在这里遗漏了一些非常明显的东西。
更新:
这有效(*),
ListInitialized(std::initializer_list<std::reference_wrapper<NonCopyable>>) {...}
,但不接受右值。如果我可以简单地传递一个可以放入const NonCopyable&
的所有内容的列表,那就太好了。
(*)我知道我写了“ no wrappers”,但这既不影响调用代码也不影响列表的迭代。
答案 0 :(得分:4)
您可以为ListInitialized
提供一个可变的构造函数模板:
struct ListInitialized
{
template <class... T>
ListInitialized(const T... &arg);
};
如果需要确保只能使用正确的类型实例化它,请考虑使用合适的SFINAE:
struct ListInitialized
{
template <
class... T,
class Sfinae = std::enable_if_t<std::is_same<std::decay_t<T>, NonCopyable> &&...
>
ListInitialized(const T... &arg);
};
答案 1 :(得分:0)
除了上面的评论和回答,我发现这个简约的包装器还可以满足我的需求:
#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
}
当然,需要注意确保通过它传递的任何右值在引用之前一直存在。