为什么这个用户定义的转换没有完成?

时间:2017-10-12 08:40:07

标签: c++ implicit-conversion

考虑:

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作为模板有关?

2 个答案:

答案 0 :(得分:4)

对于成员函数调用的对象,不考虑隐式转换,包括下标运算符重载。

考虑允许的后果:每次调用任何未声明的成员函数时,编译器必须弄清楚对象可以转换为的所有类型(请注意,任何其他不相关的类型都可能具有转换构造函数),并检查是否已声明缺少的成员函数。更不用说对于代码的读者来说会有多么混乱(转换在转换运算符的情况下可能是显而易见的,但在转换构造函数的情况下并不明显,据我所知,它们不会以其他方式区别对待)。 / p>

  

因此,有一种符合标准的方式让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。此外,它使隐式转换成为不可能(即使使用转换运算符),因此您无法在期望Prop的自由函数中将T用作T

PS。请注意,您的转换运算符返回一个值,因此必须复制向量,这可能是不合需要的。请考虑提供参考版本:

operator T&&()&&           { return *this; }
operator T&()&             { return *this; }
operator const T&() const& { return *this; }

答案 1 :(得分:1)

与任何

相同
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

Operator Dot (R3) - Bjarne Stroustrup, Gabriel Dos Rei

Smart References through Delegation: An Alternative to N4477's Operator Dot - Hubert Tong, Faisal Vali

Alternatives to operator dot - Bjarne Stroustrup