[英]Why is this user-defined conversion not done?
考虑:
template<typename T>
struct Prop
{
T value;
operator T() { return value; }
};
int main()
{
Prop<float> p1 { 5 };
Prop<std::vector<float>> p2 { { 1, 2, 3 } };
float f1 = p1; // Works fine
float f2_1_1 = p2.value[0]; // Works fine
float f2_1_2 = p2[0]; // Doesn't compile
return 0;
}
为什么标记为这样的行不能编译? 它不应该使用提供的转换运算符执行隐式转换为std::vector<>
,以便可以找到[]
吗?
该网站上还有(许多)其他问题,要求对此问题有所不同,但我找不到我认为适用于此的问题。 它与std::vector
是模板有关吗?
成员函数调用的对象(包括下标运算符重载)不考虑隐式转换。
请考虑是否允许这样做的后果:每次像这样调用任何未声明的成员函数时,编译器都必须弄清楚该对象可以转换为的所有类型(请注意,其他任何其他不相关的类型都可以具有转换构造函数),并检查是否已声明缺少成员函数。 更不用说这会对代码阅读器造成多大的混乱(在您的转换运算符情况下,转换可能很明显,但在转换构造函数的情况下却不明显,据我所知,它们在其他方面没有不同的对待)。
那么有没有一种符号上方便的方法可以使Prop表现出我想要的方式
您必须为要透明传递的vector的每个成员函数定义一个成员函数。 下面是下标运算符的示例:
auto operator[](std::size_t pos) {
return value[pos];
}
auto operator[](std::size_t pos) const {
return value[pos];
}
问题当然是必须明确声明所有包装的成员函数。 另一个问题是类型取决于T
参数。 例如, vector::operator[]
使用vector::size_type
,可能没有为您可能使用的所有T
定义(肯定不是为float
)。 在这里,我们做出妥协,并使用std::size_t
。
创建这种“透明”包装的一种较省力的方法是继承。 一个公共继承的模板将自动具有父对象的所有成员函数,并且可以隐式转换为它,并且可以由父类型的指针和引用来引用。 但是,这种方法的透明度有点问题,主要是因为~vector
不是虚拟的。
私有继承允许与您的成员方法相同的包装,但是语法好得多:
template<typename T>
struct Prop : private T
{
using T::operator[];
using T::T;
};
请注意,继承方法阻止您将基本类型用作T
另外,它使隐式转换成为不可能(即使使用转换运算符也是如此),因此您不能在期望T
自由函数中将Prop
用作T
PS。 请注意,转换运算符返回一个值,因此必须复制向量,这可能是不希望的。 考虑改为提供参考版本:
operator T&&()&& { return *this; }
operator T&()& { return *this; }
operator const T&() const& { return *this; }
与任何
p2.size();
p2.begin();
p2.push_back(24);
// etc.
编译没有意义
也
p2[0];
相当于
p2.operator[](0);
编译没有意义\\
如果您想要这种行为(即让Prop<T>
借用 T
成员),则Bjarne提出了C ++提议,将点运算符添加到语言中。 我将以与operator- ->
用于智能指针的方式相同的方式工作。 事发时有很多争议,所以我不会为此屏住呼吸。
操作员点(R3)-Bjarne Stroustrup,Gabriel Dos Rei
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.