为什么这个用户定义的转换没有完成?
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
是模板有关吗?
隐式转换不被认为是对的成员函数调用的对象,包括下标操作过载。
考虑后果如果允许的话:每次任何未声明的成员函数都是这样调用的,编译器必须找出该对象可以转换的所有类型(注意,任何其他不相关的类型都可以有一个转换构造函数),并检查是否声明了缺少的成员函数。更不用说这对代码读者会有多混淆(转换可能在转换运算符的情况下显而易见,但不在转换构造函数的情况下,并且据我所知,它们的处理方式不同)。
那么,有没有notationally方便的方式来获得道具的行为我想要的方式
你必须定义一个成员函数为每个你想传递通矢量的成员函数通过透明。以下标操作符为例:
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++提议将点运算符添加到语言中。我的工作方式与运营商->
适用于智能指针相同。 AFAIR有很多争议,所以我不会屏住呼吸。
A bit of background for the operator dot proposal—Bjarne Stroustrup
表达式'p2 [0]'实际上与'p2.operator [](0)'相同(应该可以从错误消息中推断出来)。而'Prop'类没有'operator []'函数。 –
所以问题是,p2 [0]被认为是一个表达式,对吧?因为如果p2被认为是一个表达式,转换为std :: vector将被执行,然后.operator [](0)将被调用,对吧?那么是否有一种便捷的方式让Prop以我想要的方式行事 - 即作为T型某些值的透明容器以及一些属性(因为在我的真实代码中,Prop有额外的成员)。 – Roel
像这样包装数据的常用方法是重载成员访问操作符' - >'或解引用操作符'*'。然后你可以在(0)'或者'(* p2)[0]''上做'p2->。它比较麻烦,但仍比'static_cast'好。 –