【发布时间】:2018-08-11 14:02:59
【问题描述】:
考虑以下代码:
// 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?
【问题讨论】:
-
@Barry - 有趣;重现 C++17 之前的错误的另一种方法:实现自定义
isInvocableF(),如下所示:template <typename F, typename ... Args> constexpr std::false_type isInvocableF (...) { return {}; } template <typename F, typename ... Args> constexpr auto isInvocableF (int) -> decltype( std::declval<F>()(std::declval<Args>()...), std::true_type{} ) { return {}; }。按照您的示例,调用isInvocableF<f, int>(0)您会从 g++ 获得 1 (std::true_type),从 clang++ 获得 0 (std::false_type)。 -
@Barry 不要在 cmets 中回答;您将问题留在未回答的 C++17 队列中!
-
@Yakk-AdamNevraumont 如你所愿。
标签: c++ c++17 ambiguous compiler-bug diamond-problem