【问题标题】:Is invocable and ambiguous call: bug in either g++ or clang是可调用且模棱两可的调用:g++ 或 clang 中的错误
【发布时间】: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&lt;int, float, char&gt;::operator()(int) 的调用是模棱两可的,因为该运算符被继承了两次,分别从derived1derived2 继承(假设出于复杂的SFINAE 目的,我希望它是模棱两可的)。

clang++-5.0 上,代码的输出为011,而在g++-7.2 上,输出为111。哪一个是对的?是否有解决方法,在等待错误修复时创建一个新的struct is_unambiguously_invocable

【问题讨论】:

  • @Barry - 有趣;重现 C++17 之前的错误的另一种方法:实现自定义 isInvocableF(),如下所示:template &lt;typename F, typename ... Args&gt; constexpr std::false_type isInvocableF (...) { return {}; } template &lt;typename F, typename ... Args&gt; constexpr auto isInvocableF (int) -&gt; decltype( std::declval&lt;F&gt;()(std::declval&lt;Args&gt;()...), std::true_type{} ) { return {}; }。按照您的示例,调用 isInvocableF&lt;f, int&gt;(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


【解决方案1】:

你的推理是正确的。请注意,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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-07
    • 2014-09-28
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 2014-08-06
    相关资源
    最近更新 更多