是可调用且模棱两可的调用:g++ 或 clang 中的错误
Is invocable and ambiguous call: bug in either g++ or clang
考虑以下代码:
// Preamble
#include <iostream>
#include <type_traits>
// A base class
template <class T>
struct base {void operator()(T){};};
// Two derived classes inheriting from the same base classes
template <class... T>
struct derived1: base<T>... {using base<T>::operator()...;};
template <class... T>
struct derived2: base<T>... {using base<T>::operator()...;};
// A class inheriting from both derived1 and derived2
template <class T0, class... T>
struct functor: derived1<T0>, derived2<T0, T...> {
using derived1<T0>::operator();
using derived2<T0, T...>::operator();
};
// Main function
int main() {
std::cout << std::is_invocable_v<functor<int, float, char>, int> << "\n";
std::cout << std::is_invocable_v<functor<int, float, char>, float> << "\n";
std::cout << std::is_invocable_v<functor<int, float, char>, char> << "\n";
return 0;
}
对 functor<int, float, char>::operator()(int)
的调用是不明确的,因为此运算符从 derived1
和 derived2
继承了两次(假设为了复杂的 SFINAE 目的,我希望它是不明确的).
在 clang++-5.0
上,代码的输出是 0
、1
、1
,而在 g++-7.2
上,输出是 1
, 1
, 1
。哪一个是对的?是否有解决方法,在等待错误修复的同时创建一个新的 struct is_unambiguously_invocable
?
你的推理是正确的。请注意,gcc 正确地禁止调用本身:
functor<int, float, char>()(42); // error: base<int> is an ambiguous base
它只是错误地检测到此调用格式错误。报告为 gcc bug 84869。 T.C。在没有库依赖性的错误报告中添加了进一步减少的复制:
struct base {
void operator()(int ) { }
};
struct a : base { };
struct b : base { };
struct f: a, b {
using a::operator();
using b::operator();
};
template<class T> auto g(int) -> decltype(T()(0), 0);
template<class T> auto g(...) -> long;
template<class, class> struct Same;
template<class T> struct Same<T, T> {};
Same<decltype(g<f>(0)), long> s; // should be okay, but gcc errors because it
// thinks decltype(g<f>(0)) is int
考虑以下代码:
// Preamble
#include <iostream>
#include <type_traits>
// A base class
template <class T>
struct base {void operator()(T){};};
// Two derived classes inheriting from the same base classes
template <class... T>
struct derived1: base<T>... {using base<T>::operator()...;};
template <class... T>
struct derived2: base<T>... {using base<T>::operator()...;};
// A class inheriting from both derived1 and derived2
template <class T0, class... T>
struct functor: derived1<T0>, derived2<T0, T...> {
using derived1<T0>::operator();
using derived2<T0, T...>::operator();
};
// Main function
int main() {
std::cout << std::is_invocable_v<functor<int, float, char>, int> << "\n";
std::cout << std::is_invocable_v<functor<int, float, char>, float> << "\n";
std::cout << std::is_invocable_v<functor<int, float, char>, char> << "\n";
return 0;
}
对 functor<int, float, char>::operator()(int)
的调用是不明确的,因为此运算符从 derived1
和 derived2
继承了两次(假设为了复杂的 SFINAE 目的,我希望它是不明确的).
在 clang++-5.0
上,代码的输出是 0
、1
、1
,而在 g++-7.2
上,输出是 1
, 1
, 1
。哪一个是对的?是否有解决方法,在等待错误修复的同时创建一个新的 struct is_unambiguously_invocable
?
你的推理是正确的。请注意,gcc 正确地禁止调用本身:
functor<int, float, char>()(42); // error: base<int> is an ambiguous base
它只是错误地检测到此调用格式错误。报告为 gcc bug 84869。 T.C。在没有库依赖性的错误报告中添加了进一步减少的复制:
struct base { void operator()(int ) { } }; struct a : base { }; struct b : base { }; struct f: a, b { using a::operator(); using b::operator(); }; template<class T> auto g(int) -> decltype(T()(0), 0); template<class T> auto g(...) -> long; template<class, class> struct Same; template<class T> struct Same<T, T> {}; Same<decltype(g<f>(0)), long> s; // should be okay, but gcc errors because it // thinks decltype(g<f>(0)) is int