0 c++ oop inheritance stl vector
我从这个维基复制了代码并且它有效。
当我编写这段代码时出现问题:
int main()
{
std::set<int> random_s = getRandomN(10);
std::vector<int> random_v;
random_v = getRandomN(10);
std::list<int> random_l = getRandomN(10);
}
Run Code Online (Sandbox Code Playgroud)
我的编译器(gcc trunk)打印出以下错误:
error: ambiguous overload for 'operator=' (operand types are 'std::vector<int, std::allocator<int> >' and 'getRandomN')
43 | random_v = getRandomN(10);
Run Code Online (Sandbox Code Playgroud)
我不明白为什么 C++ 编译器不能简单地采用copy operator=
而是尝试匹配operator=(initializer_list<value_type> __l)
and operator=(vector&& __x)
。
这是我对这个问题的解决方案,我不喜欢它,但我想不出其他的办法:
功能演员表:
random_v = std::vector<int>(getRandomN(10));
Run Code Online (Sandbox Code Playgroud)
显然,该类型必须重复两次。
私有继承并从父级转发所需的方法:
template<typename T>
class my_vector : private std::vector<T>
{
public:
using std::vector<T>::end;
using std::vector<T>::insert;
my_vector<int>& operator=(my_vector<int> rhs) noexcept
{
std::swap(*this, rhs);
return *this;
}
};
my_vector<int> random_v1;
random_v1 = getRandomN(10);
Run Code Online (Sandbox Code Playgroud)
很明显,我不再使用了std::vector<int>
...
完整代码:godbolt
问题在于,仅从转换运算符的签名来看,编译器无法判断它是否应该转换getRandomN(10)
为 astd::initializer_list<int>
然后将其分配给random_v
,或者转换getRandomN(10)
为 astd::vector<int>
然后将其分配给random_v
。两者都只涉及一个用户定义的转换,因此从编译器的角度来看都不是更好的选择。
当然,一旦您查看转换运算符的主体,就会发现它std::initializer_list<int>
不起作用,因为它没有insert
成员函数,但为时已晚。编译器在查看函数体之前选择重载决策。
实现这一目标的方法是明确表明std::initializer_list<int>
仅从签名来看这并不是正确的选择。如果您能够了解 C++20 概念,那么这非常简单:
template <typename T>
concept BackInsertable = requires(T t) { t.insert(std::end(t), 0); };
class getRandomN
{
size_t count;
public:
getRandomN(int n = 1) : count(n) {}
// ------ vvvvvvvvvvvvvv ------ NOTE HERE
template <BackInsertable Container>
operator Container () {
Container c;
for(size_t i = 0;i < count; ++i)
c.insert(c.end(), rand()); // push_back is not supported by all standard containers.
return c;
}
};
Run Code Online (Sandbox Code Playgroud)
如果没有概念,您将需要使用其他 SFINAE 技巧来使该运算符无效。下面是一种可以一直追溯到 C++11 的可能实现:
template <typename T>
using BackInsertable = decltype(std::declval<T&>().insert(std::end(std::declval<T&>()), 0));
class getRandomN
{
size_t count;
public:
getRandomN(int n = 1) : count(n) {}
template <typename Container, BackInsertable<Container>* = nullptr>
operator Container () {
Container c;
for(size_t i = 0;i < count; ++i)
c.insert(c.end(), rand()); // push_back is not supported by all standard containers.
return c;
}
};
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
115 次 |
最近记录: |