为什么 GCC 不能使用声明为正确的类型解决此问题

why can't GCC resolve this using declaration to the correct type

本文关键字:类型 解决 问题 不能 GCC 声明 为什么      更新时间:2023-10-16

当我在一个项目中编码时,我发现了一些非常奇怪的事情:

namespace detail {
    struct tuplelike_tag { };
    struct arraylike_tag { };
    template<typename>
    struct call_with_traits;
    template<typename... Ts>
    struct call_with_traits<std::tuple<Ts...>> {
        using tag = tuplelike_tag;
        enum { size = sizeof...(Ts) };
    };
    template<typename T, std::size_t Sz>
    struct call_with_traits<std::array<T, Sz>> {
        using tag = arraylike_tag;
        enum { size = Sz };
    };
    template<typename T, std::size_t Sz>
    struct call_with_traits<T[Sz]> {
        using tag = arraylike_tag;
        enum { size = Sz };
    };
    template<typename F, typename T, int... Is>
    auto call_with(F && f, T && tup, indices<Is...>, tuplelike_tag) -> ResultOf<Unqualified<F>> {
        return (std::forward<F>(f))(std::get<Is>(std::forward<T>(tup))...);
    }
    template<typename F, typename A, int... Is>
    auto call_with(F && f, A && arr, indices<Is...>, arraylike_tag) -> ResultOf<Unqualified<F>> {
        return (std::forward<F>(f))(std::forward<A>(arr)[Is]...);
    }
}
template<typename F, typename Cont>
inline auto call_with(F && f, Cont && cont) -> ResultOf<Unqualified<F>> {
    using unqualified = Unqualified<Cont>;
    using traits  = typename detail::call_with_traits<unqualified>;
    using tag     = typename detail::call_with_traits<unqualified>::tag;
    using no_tag  = typename traits::tag;   // this is what it's all about
    return detail::call_with(std::forward<F>(f), std::forward<Cont>(cont), build_indices<traits::size>(), tag());
}
这段代码的奇怪之处在于标签被解析为typename detail::call_with_traits::tag;,但是no_tag错误输出:
error: no type named ‘tag’ in ‘using traits = struct detail::call_with_traits<typename std::remove_cv<typename std::remove_reference<_To>::type>::type>’

,即使它应该在同一结构体中引用相同的using声明。是我错过了什么,还是这是GCC中的一些bug ?

可以在这里找到一个实例,包括来自GCC的相关错误消息。

这似乎是g++ 4.7.2中的一个bug。下面是一个简单的例子:

template<typename> struct A { using tag = int; };
template<typename T>
inline void f() {
  using AT = A<T>;
  typename A<T>::tag x; // no error
  typename   AT::tag y; // error
}
int main(int argc, char ** argv) {
  f<int>();
  return 0;
}

如果使用typedef而不是using声明,或者使用A<int>而不是A<T>,则不会出现错误