#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会使代码编译并按预期使用转换运算符.为什么这些无法访问的操作符在无法访问的继承操作符时不会出现问题?
解决方法
C 11:
f
shall beCallable
for argument typesArgTypes
and return typeR
.
C 14:
Shall not participate in overload resolution unless
f
isCallable
for argument typesArgTypes...
and return typeR
.
在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的机制相同.