【问题标题】:g++ and clang++ - delete pointer acquired by overloaded conversion operator ambiguityg++ 和 clang++ - 重载转换运算符歧义获取的删除指针
【发布时间】:2015-12-19 14:36:40
【问题描述】:

我试图通过制作此指针包装器(替换原始指针)将此代码作为对this question 的回答。这个想法是将const 委托给它的指针,这样filter 函数就不能修改这些值。

#include <iostream>
#include <vector>

template <typename T>
class my_pointer
{
    T *ptr_;

public:
    my_pointer(T *ptr = nullptr) : ptr_(ptr) {}

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

std::vector<my_pointer<int>> filter(std::vector<my_pointer<int>> const& vec)
{
    //*vec.front() = 5; // this is supposed to be an error by requirement
    return {};
}

int main()
{
    std::vector<my_pointer<int>> vec = {new int(0)};
    filter(vec);
    delete vec.front(); // ambiguity with g++ and clang++
}

Visual C++ 12 和 14 编译它没有错误,但 GCC 和 Clang on Coliru 声称存在歧义。我期待他们选择非常量 std::vector::front 重载,然后选择 my_pointer::operator T* &amp;,但没有。这是为什么呢?

【问题讨论】:

  • 尝试让 const 重载也返回一个引用
  • 基本上,标准说编译器需要首先决定要转换成什么,然后运行重载决议。但在这里它在第一步失败,因为int*const int* 都是上下文允许的。

标签: c++ c++11 c++14 ambiguous


【解决方案1】:

[expr.delete]/1:

操作数应该是指向对象类型或类类型的指针。如果 类类型,操作数在上下文中隐式转换(子句 [conv]) 指向对象类型的指针。

[conv]/5,强调我的:

某些语言结构需要转换为具有 1 的值 适用于构造的一组指定类型。一个 表示出现在这种上下文中的类类型 E 的表达式 e上下文隐式转换到指定类型T和 当且仅当 e 可以隐式转换为类型时,是格式良好的 T 确定如下:E 被搜索为非显式 返回类型为cv T 或引用cv T 的转换函数 这样T 是上下文允许的。 应该有 一个这样的T

在您的代码中,有两个这样的Ts(int *const int *)。因此,在您进行重载决议之前,它的格式不正确。


请注意,在 C++11 和 C++14 之间,这方面的内容有所不同。 C++11 [expr.delete]/1-2 说

操作数应该有一个指向对象类型或类类型的指针 具有指向指针的单个非显式转换函数(12.3.2) 对象类型。 [...]

如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,[...]

如果从字面上理解,这将允许您的代码并始终调用operator const int*() const,因为int* &amp; 是引用类型,而不是指向对象类型的指针。在实践中,实现也会将转换函数考虑为“对对象指针的引用”,例如operator int*&amp;(),然后拒绝该代码,因为它具有多个符合条件的非显式转换函数。

【讨论】:

  • 我刚刚尝试添加get 函数和it worked,所以这只发生在隐式转换运算符?
  • @LogicStuff 正确。调用成员函数只是做普通的重载决议,如果它返回一个指针delete 是快乐的。
【解决方案2】:

delete 表达式将转换表达式作为参数,可以是 const 也可以不是。

vec.front() 不是 const,但必须首先将其转换为delete 的指针。所以const int*int*都是可能的候选人;编译器无法选择您想要的。

最简单的方法是使用强制转换来解决选择。例如:

delete (int*)vec.front();

备注:当您使用get() 函数而不是转换时,它会起作用,因为规则不同。重载函数的选择基于参数和对象的类型,而不是返回类型。这里的非 const 是 best viable 函数,因为 vec.front() 不是 const。

【讨论】:

  • 我不认为这是一个完整的答案,因为编译器总是为非常量对象选择非常量版本的函数来进行正常的函数调用。这种情况下没有歧义,那么为什么要在这种情况下呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2012-05-21
  • 2021-05-02
  • 2021-07-02
相关资源
最近更新 更多