代码之家  ›  专栏  ›  技术社区  ›  Guillaume Racicot

模板转换运算符的分辨率不明确

  •  6
  • Guillaume Racicot  · 技术社区  · 7 年前

    我不得不做一个类似的代码:

    #include <type_traits>
    
    template<typename S>
    struct probe {
        template<typename T, typename U = S, std::enable_if_t<
            std::is_same<T&, U>::value &&
            !std::is_const<T>::value, int> = 0>
        operator T& () const;
    
        template<typename T, typename U = S&&, std::enable_if_t<
            std::is_same<T&&, U>::value &&
            !std::is_const<T>::value, int> = 0>
        operator T&& ();
    
        template<typename T, typename U = S, std::enable_if_t<
            std::is_same<T const&, U>::value, int> = 0>
        operator T const& () const;
    
        template<typename T, typename U = S&&, std::enable_if_t<
            std::is_same<T const&&, U>::value, int> = 0>
        operator T const&& () const;
    };
    
    struct some_type {};
    struct other_type {};
    
    auto test_call(some_type const&, other_type) -> std::false_type;
    auto test_call(some_type&, other_type) -> std::true_type;
    
    int main() {
        static_assert(decltype(test_call(probe<some_type&>{}, other_type{}))::value, "");
    }
    

    它可以在gcc和clang下工作,但不能在Visual Studio上编译,因为存在不明确的分辨率错误。哪个编译器错误,为什么?

    GCC and Clang ,请 Visual studio

    以下是MSVC输出:

    source_file.cpp(31): error C2668: 'test_call': ambiguous call to overloaded function
    source_file.cpp(28): note: could be 'std::true_type test_call(some_type &,other_type)'
    source_file.cpp(27): note: or       'std::false_type test_call(const some_type &,other_type)'
    source_file.cpp(31): note: while trying to match the argument list '(probe<some_type &>, other_type)'
    source_file.cpp(31): error C2651: 'unknown-type': left of '::' must be a class, struct or union
    source_file.cpp(31): error C2062: type 'unknown-type' unexpected
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   xskxzr    7 年前

    代码可以简化为 the following

    #include <type_traits>
    
    struct some_type {};
    
    struct probe {
        template<typename T, std::enable_if_t<!std::is_const<T>::value, int> = 0>
        operator T& () const;
    };
    
    auto test_call(some_type const&) -> std::false_type;
    auto test_call(some_type&) -> std::true_type;
    
    int main() {
        static_assert(decltype(test_call(probe{}))::value, "");
    }
    

    5 6

    一般来说,推导过程试图找到模板参数值,使推导出的值与a相同。但是,有四种情况允许差异:

    • ……

    T some_type 对于两个函数调用。然后根据[超过.ics.等级]。/ 3.3

    probe -> some_type& -> some_type& probe -> some_type& -> const some_type& 所以没有歧义,GCC和Clang是对的。


    顺便说一句,如果我们移除 std::enable_if_t<...> test_all

    #include <type_traits>
    
    struct some_type {};
    
    struct probe {
        template<typename T>
        operator T& () const
        {
            static_assert(std::is_const_v<T>);
            static T t;
            return t;
        }
    };
    
    auto test_call(some_type const&) -> std::false_type;
    
    int main() {
        test_call(probe{});
    }
    

    static_assert only under Clang .也就是说,Clang推断 一些类型 const some_type

    推荐文章