10

如果定义了 BREAK,g++ 4.6.3 和 4.7.2 将无法编译以下代码(在 c++0x 模式下)。

template<class T> struct Test {
    Test(T&) {}
#ifdef BREAK
    Test(T&&) = delete;
#endif
};

void func(Test<int> const&) {}
void func(Test<double> const&) {}

int main()
{
    int x = 0;
    func(x);
    return 0;
}

错误是

error: call of overloaded 'func(int&)' is ambiguous

而 clang 3.2 RC2 和 VC11 (如果我替换Test(T&&) = delete;private: Test(T&&);)接受代码。

我看不出哪里应该模棱两可。

这是一个 g++ 问题吗?(我不知道在 gcc 错误列表中搜索什么......)

4

2 回答 2

6

已删除的构造函数参与重载决议(是否始终声明特殊成员函数?);这是必要的,以便可以使用已删除的构造函数来防止转换(摘自 8.4.3p3):

struct onlydouble {
  onlydouble(std::intmax_t) = delete;
  onlydouble(double);
};

函数删除的执行在编译过程中很晚,在重载决议(8.4.3p2)之后,因此重载决议无法根据删除区分构造函数。gcc 是正确的,而 clang 和 VC11 是不正确的。

请注意,在函数调用表达式中存在歧义func(x),其中参数x是类型的左值,intid表示在 and 的第一个(唯一)参数中func具有参数类型的重载集;那么可用的转换序列是:const Test<int> &const Test<double> &

  1. int左值;int &; Test<int>暂时的; const Test<int> &,
  2. int左值;int右值;double右值;double &&; Test<double>暂时的; const Test<double> &.

这两个序列是用户定义的等秩转换序列,因此是模棱两可的。Test<double>::Test(double &&)在这个阶段,构造函数被删除的事实是无关紧要的。

于 2012-12-04T13:22:39.227 回答
1

GCC 中有一个开放的错误: http://gcc.gnu.org/bugzilla/show_bug.cgi?id= 54425

CLANG 是正确的,GCC 需要解决这个问题。

于 2012-12-04T14:43:20.797 回答