c – 为什么g从具有转换运算符和不可访问的函数调用运算符的类型的std :: function <>初始化失败?

前端之家收集整理的这篇文章主要介绍了c – 为什么g从具有转换运算符和不可访问的函数调用运算符的类型的std :: function <>初始化失败?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
代码在g 4.9及更高版本(包括从svn current构建时)失败,但是使用clang和microsofts编译器(来自VS2015)编译时没有警告.
#include <functional>

struct A {
  void operator()() const {}
};
struct B {
  void operator()() const {}
};
struct C : private A,private B
{
  operator std::function<void()>() const { return nullptr; }
};

int main()
{
  std::function<void()> f{C{}};
}

由于operator()在struct C中不明确,main()中f的构造失败.

为什么g认为这是模棱两可的? C中的函数调用操作符是私有继承的,不可访问.
向struct C添加一个私有或显式删除的void operator()()const会使代码编译并按预期使用转换运算符.为什么这些无法访问的操作符在无法访问的继承操作符时不会出现问题?

解决方法

构造函数:template< class F>功能(F f);

C 11:

f shall be Callable for argument types ArgTypes and return type R.

C 14:

Shall not participate in overload resolution unless f is Callable for argument types ArgTypes... and return type R.

在C 11中,此构造函数模板比​​涉及std :: function移动构造函数用户定义的转换运算符的转换序列更好地匹配.因此,重载决策选择构造函数模板,然后由于f不可调用而无法编译.

在C 14中,构造函数模板会发生替换失败,因为f不可调用.因此构造函数模板不参与重载解析,最好的剩余匹配是涉及std :: function移动构造函数用户定义的转换运算符的转换序列,因此使用它.

Clang以C 11和C 14模式编译您的测试用例. GCC在C 11和C 14模式下拒绝您的测试用例.这是另一个在GCC中演示相同问题的测试用例:

#include <type_traits>

struct A {
  void operator()() const {}
};
struct B {
  void operator()() const {}
};
struct C : A,B {};

template <typename F,typename = std::result_of_t<F&()>>
void test(int) {}

template <typename F>
void test(double) {}

int main() {
  test<C>(42);
}

test(int)不应该参与重载决策,因为std :: result_of_t< F&()>应该是替换失败,所以应该调用test(double).但是,此代码无法在GCC中编译.

这是在您的测试用例中看到的相同问题,因为这与用于在libstdc中的std :: function的构造函数模板中实现SFINAE的机制相同.

猜你在找的C&C++相关文章