簡體   English   中英

為什么std :: is_function對於簡單函數和lambdas返回false?

[英]Why std::is_function returns false for simple functions and lambdas?

擁有以下代碼:

#include <iostream>
#include <type_traits>

template <typename F,
          typename = typename std::enable_if<
                                              std::is_function< F >::value
                                            >::type>
int fun( F f ) // line 8
{
  return f(3);
}

int l7(int x)
{
  return x%7;
}

int main()
{
  auto l = [](int x) -> int{
    return x%7;
  };
  fun(l);  // line 23
  //fun(l7); this will also fail even though l7 is a regular function

  std::cout << std::is_function<decltype(l7)>::value ; // prints 1
}

我會收到以下錯誤:

main2.cpp: In function ‘int main()’:
main2.cpp:23:8: error: no matching function for call to ‘fun(main()::<lambda(int)>&)’
   fun(l);
        ^
main2.cpp:8:5: note: candidate: template<class F, class> int fun(F)
 int fun( F f )
     ^
main2.cpp:8:5: note:   template argument deduction/substitution failed:
main2.cpp:5:11: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
           typename = typename std::enable_if<
           ^

當我注釋掉std::enable_if模板參數時,它編譯並運行就好了。 為什么?

cppreference

檢查T是否為函數類型。 類似std::function ,lambdas,帶有重載operator()的類和指向函數的指針都不算作函數類型。

這個答案解釋了你還需要使用std::remove_pointer<F>::type作為類型,因為函數在傳遞值時會轉換為指向函數的指針。 所以你的代碼應該是這樣的:

template <typename F,
          typename = typename std::enable_if<
                                              std::is_function<
                                                typename std::remove_pointer<F>::type
                                              >::value
                                            >::type>
int fun( F f )
{
  return f(3);
}

解決此問題的另一種方法是編寫更具體的類型特征。 例如,這一個檢查參數類型是否可轉換並適用於任何可調用的東西。

#include <iostream>
#include <type_traits>
#include <utility>
#include <string>

template<class T, class...Args>
struct is_callable
{
    template<class U> static auto test(U*p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());

    template<class U> static auto test(...) -> decltype(std::false_type());

    static constexpr auto value = decltype(test<T>(nullptr))::value;
};

template<class T, class...Args>
static constexpr auto CallableWith = is_callable<T, Args...>::value;


template <typename F,
std::enable_if_t<
CallableWith<F, int>
>* = nullptr
>
int fun( F f ) // line 8
{
    return f(3);
}

int l7(int x)
{
    return x%7;
}

int main()
{
    auto l = [](int x) -> int{
        return x%7;
    };

    std::cout << "fun(l) returns " << fun(l) << std::endl;

    std::cout << CallableWith<decltype(l7), int> << std::endl;    // prints 1
    std::cout << CallableWith<decltype(l7), float> << std::endl;  // prints 1 because float converts to int
    std::cout << CallableWith<decltype(l7), const std::string&> << std::endl; // prints 0
}

看看std::is_invocable ,它也涵蓋了C ++ 17中的lambdas( std::is_callable不存在)。

暫無
暫無

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

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