Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 检测是否定义了具有特定签名的函数/运算符/方法_C++_Sfinae - Fatal编程技术网

C++ 检测是否定义了具有特定签名的函数/运算符/方法

C++ 检测是否定义了具有特定签名的函数/运算符/方法,c++,sfinae,C++,Sfinae,从这个问题出发,我们如何在编译时检测是否定义了具有特定签名的函数/运算符/方法 通过链接的问题和参考资料,我们可以提前编写C++17 #include<iostream> #include<type_traits> #include<utility> class X { public: int someFunc() const{ return 9; } }; class Y{}; template<typename, typename = std::

从这个问题出发,我们如何在编译时检测是否定义了具有特定签名的函数/运算符/方法

通过链接的问题和参考资料,我们可以提前编写C++17

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

class X { public: int someFunc() const{ return 9; } };
class Y{};

template<typename, typename = std::void_t<>> struct Has_someFunc
    : std::false_type{};
template<typename T> struct Has_someFunc<T, std::void_t<decltype(std::declval<T>().someFunc())>>
    : std::true_type{};

template<typename T>
void f(const T& v){
    if constexpr(Has_someFunc<T>::value)
        std::cout << "has someFunc()\n";
    else
        std::cout << "has NOT someFunc()\n";
}

int main()
{
    std::cout << "X "; f(X{});
    std::cout << "Y "; f(Y{});

    return 0;
}
但是,如果我们想测试一个类型,使其不仅要定义someFunc,而且还要具有特定的签名,该怎么办


尽管我使用的是C++17,但也欢迎在标准的任何其他版本中使用答案。

如果您想检查某个类型是否有一个方法someFunc,该方法在vocable中与给定签名兼容并返回给定类型,您可以按如下方式修改代码

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

class X
 { public: int someFunc (int, long) const { return 9; } };

class Y
 { };

template <typename, typename = void>
struct Has_someFunc : public std::false_type
 { };

template <typename T, typename RType, typename ... Args>
struct Has_someFunc<std::tuple<T, RType, Args...>, std::enable_if_t<
   std::is_same_v<RType, 
      decltype(std::declval<T>().someFunc(std::declval<Args>()...))>>>
    : public std::true_type
 { };

template <typename RType, typename ... Args, typename T>
void f (T const & v)
 {
   if constexpr (Has_someFunc<std::tuple<T, RType, Args...>>::value)
      std::cout << "has someFunc()\n";
   else
      std::cout << "has NOT someFunc()\n";
 }

int main()
{
    std::cout << "X "; f<int>(X{});
    std::cout << "X "; f<int, int, long>(X{});
    std::cout << "X "; f<int, int, int>(X{});
    std::cout << "Y "; f<int>(Y{});
}

缺点:由于最后一个参数a int与最后一个预期参数a long兼容,因此第三次调用时也会得到someFunc。

您想知道someFunc是否可以使用给定的签名进行调用这很简单,从代码开始,还是存在一个完全具有给定签名的someFunc?在第二种情况下:如果有一个与给定签名兼容的模板someFunc呢?对于我当前的需要,你的第一句话就足够了,也就是说,如果我可以使用可转换为现有参数的参数调用该方法,然后返回一个可转换为所需类型的结果。但我也想知道如何对类型更严格。为第一种情况添加了一个答案:对代码进行简单修改。如果你想更严格地检查一个准确的签名。。。也许你应该解释清楚你到底想要什么。
#include<iostream>
#include<type_traits>
#include<utility>

class X
 { public: int someFunc (int, long) const { return 9; } };

class Y
 { };

template <typename, typename = void>
struct Has_someFunc : public std::false_type
 { };

template <typename T, typename RType, typename ... Args>
struct Has_someFunc<std::tuple<T, RType, Args...>, std::enable_if_t<
   std::is_same_v<RType, 
      decltype(std::declval<T>().someFunc(std::declval<Args>()...))>>>
    : public std::true_type
 { };

template <typename RType, typename ... Args, typename T>
void f (T const & v)
 {
   if constexpr (Has_someFunc<std::tuple<T, RType, Args...>>::value)
      std::cout << "has someFunc()\n";
   else
      std::cout << "has NOT someFunc()\n";
 }

int main()
{
    std::cout << "X "; f<int>(X{});
    std::cout << "X "; f<int, int, long>(X{});
    std::cout << "X "; f<int, int, int>(X{});
    std::cout << "Y "; f<int>(Y{});
}