簡體   English   中英

std::is_invocable 在模板類型上的意外結果

[英]Unexpected result of std::is_invocable over a template type

我有一個if constexpr檢查類型是否與自身相等。 我使用std::is_invocable_v<std::equal_to<>, T, T>

然而,當T是一個由不可比結構組成的向量時,代碼片段會錯誤地返回 True。 有什么深層原因還是編譯器錯誤?

最小的例子如下。

#include <type_traits>
#include <iostream>
#include <vector>

class TNonComparable{};

int main()
{
    std::cout << std::is_invocable_v<std::equal_to<>, TNonComparable, TNonComparable> << "\n";
    // 0

    std::cout << std::is_invocable_v<
            std::equal_to<>,
            std::vector<TNonComparable>,
            std::vector<TNonComparable>
        > << "\n";
    // 1

    std::vector<TNonComparable> vec;
    // vec == vec;
    // (expected) compilation error
}

我檢查了 Godbolt 的輸出,所有最新版本的 g++ 和 clang 都是一樣的。

我認為查看std::is_invocable的作用非常重要:

確定是否可以使用參數ArgTypes...調用Fn 正式地,確定INVOKE(declval<Fn>(), declval<ArgTypes>()...)在被視為未計算的操作數時是否格式良好,其中INVOKECallable定義的操作

強調我的。

這里要注意的重要部分是std::equal_to<>std::is_invocable使用的永遠不會被求值,因為它是一個未求值的操作數。 這意味着它只檢查operator==存在,它對std::vector<> ,而不是它是否會在評估的上下文中編譯。

我認為,這是正確的行為。

在第一個std::is_invokable_v檢查TNonComparable類型中operator==的存在。 它不存在 - 所以結果是 0。

在第二種情況下, std::is_invokable_v檢查std::vector的相等運算符,該運算符存在並可被調用。 但是如果嘗試調用它,它將無法編譯,因為TNonComparable類型沒有operator== 但是在您不嘗試使用它之前,它不會產生錯誤。

也許,在第二種情況下,您應該檢查 std::vector 的 value_type:

std::cout << std::is_invocable_v<
        std::equal_to<>,
        std::vector<TNonComparable>::value_type,
        std::vector<TNonComparable>::value_type
    > << "\n";
// 0

有一些時間,我寫了解決方法工具

namespace detail
{
    template<typename T, typename=void>
    struct has_value_type : std::false_type {};

    template<typename T>
    struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type {};

    template<typename T, typename=void>
    struct is_pair : std::false_type {};

    template<typename T, typename U>
    struct is_pair<std::pair<T, U>, void> : std::true_type {};

    template<typename T, typename=void>
    struct is_tuple : std::false_type {};

    template<typename ...Args>
    struct is_tuple<std::tuple<Args...>, void> : std::true_type {};
}

template<typename T, typename=void>
struct has_euqual_operator : std::false_type {};

template<typename T>
struct has_euqual_operator<
        T, 
        std::void_t<
            std::enable_if_t<
                !detail::is_pair<T>::value 
                && !detail::has_value_type<T>::value 
                && !detail::is_tuple<T>::value>,
            decltype(std::declval<T>() == std::declval<T>())
        >
    > : std::true_type 
{};

template<typename T>
struct has_euqual_operator<
        T, 
        std::enable_if_t<has_euqual_operator<typename T::value_type>::value>
    > : std::true_type 
{};

template<typename T>
struct has_euqual_operator<
        T, 
        std::enable_if_t<has_euqual_operator<typename T::first_type>::value
            && has_euqual_operator<typename T::second_type>::value
        >
    > : std::true_type 
{};

template<typename ...Args>
struct has_euqual_operator<
        std::tuple<Args...>, 
        std::enable_if_t<(... && has_euqual_operator<Args>::value)>
    > : std::true_type 
{};

https://godbolt.org/z/rcejhx

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM